<?php

namespace KupShop\AdminBundle\Util;

use KupShop\AdminBundle\AdminList\BaseList;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Excel\ExcelGenerator;
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
use KupShop\KupShopBundle\Util\StringUtil;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class ListExporter
{
    /**
     * @var ExportListObject
     */
    protected $exportListObject;

    public function listExport()
    {
        $table = $this->exportListObject->getColumns();
        $this->excelExporter($table);
    }

    public function excelExporter($table)
    {
        ini_set('memory_limit', '1G');
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        // header
        $columnIndex = 1;
        foreach ($table['fields'] as $key => $value) {
            if ($value['visible'] == 'Y') {
                $sheet->setCellValueByColumnAndRow($columnIndex, 1, $value['title']);
            } else {
                continue;
            }
            if (!empty($value['width']) && is_numeric($value['width'])) {
                $sheet->getColumnDimensionByColumn($columnIndex)->setWidth($value['width']);
            }

            // First data line - get column data type
            $type = $this->getColumnType($value);
            switch ($type) {
                case BaseList::TYPE_INT:
                case BaseList::TYPE_PRICE:
                case BaseList::TYPE_FLOAT:
                    $sheet->setCellValueExplicitByColumnAndRow($columnIndex, 2, 1.1, DataType::TYPE_NUMERIC);
                    break;

                case BaseList::TYPE_DATETIME:
                case BaseList::TYPE_DATE:
                    $sheet->setCellValueExplicitByColumnAndRow($columnIndex,
                        2,
                        Date::dateTimeToExcel(new \DateTime()),
                        DataType::TYPE_NUMERIC);

                    $sheet->getCellByColumnAndRow($columnIndex, 2)->getStyle()->getNumberFormat()
                        ->setFormatCode($type == BaseList::TYPE_DATETIME ? NumberFormat::FORMAT_DATE_DATETIME : NumberFormat::FORMAT_DATE_DMYSLASH);
                    break;

                case BaseList::TYPE_STRING:
                    $sheet->setCellValueExplicitByColumnAndRow($columnIndex, 2, 'a', DataType::TYPE_STRING);
            }

            $sheet->getColumnDimensionByColumn($columnIndex)->setAutoSize(true);

            $columnIndex++;
        }

        $spreadsheet->setActiveSheetIndex(0);
        $filename = 'export_'.$this->exportListObject->getObject()->getListName().'_'.date('Y-m-d_H-i').'.xlsx';
        $template = 'data/tmp/'.uniqid().'.xls';
        $objWriter = new Xlsx($spreadsheet);
        $objWriter->save($template);

        /** @var ExcelGenerator $generator */
        $generator = ServiceContainer::getService(ExcelGenerator::class);
        $generator->generateExcel([], $this->getData(), $filename, $template);
    }

    /**
     * @param $listObject BaseList
     *
     * @throws \Exception
     */
    public function setListObject($listObject): void
    {
        $this->exportListObject->setObject($listObject);
    }

    /**
     * @required
     */
    public function setExportListObject(ExportListObject $exportListObject): void
    {
        $this->exportListObject = $exportListObject;
    }

    protected function getData(): \Generator
    {
        $ab = [];
        $qb = $this->exportListObject->getObject()->getFinalQueryBuilder($ab);
        $data = $qb->execute();
        $table = $this->exportListObject->getTableDef()['fields'];
        foreach ($data as $values) {
            $output = [];
            foreach ($table as $column) {
                if ((getVal('wpjAdmin', $column) and !isSuperuser()) || ($column['visible'] == 'N')) {
                    continue;
                }
                $value = $this->exportListObject->render($column, $values, null);
                if ($value === null) {
                    $value = '';
                }
                if (!is_array($value)) {
                    $value = [$value];
                }

                foreach ($value as &$pvalue) {
                    if ($pvalue instanceof HTML) {
                        // Print value of input
                        if ($pvalue->getName() === 'input') {
                            $pvalue = $pvalue->getAttribute('value');
                        } else {
                            $pvalue = strip_tags($pvalue->html());
                        }
                    }
                }
                $to_add = join('', $value);
                if ($to_add == '') {
                    $to_add = null;
                }

                $type = $this->getColumnType($column);
                if (in_array($type, [BaseList::TYPE_PRICE, BaseList::TYPE_FLOAT]) !== false) {
                    // Convert string to number
                    $to_add = floatval(str_replace([',', ' '], ['.', ''], $to_add));
                }

                $output[] = $to_add;
            }
            yield $output;
        }
    }

    protected function getColumnType($column)
    {
        $renderer = $column['render'] ?? null;

        if (!$renderer) {
            return BaseList::TYPE_STRING;
        }

        if (StringUtil::startsWith($renderer, 'renderPrice') || StringUtil::startsWith($renderer, 'renderFormatPrice')) {
            return BaseList::TYPE_PRICE;
        }

        if (StringUtil::startsWith($renderer, 'renderDateTime')) {
            return BaseList::TYPE_DATETIME;
        }

        if (StringUtil::startsWith($renderer, 'renderDate')) {
            return BaseList::TYPE_DATE;
        }

        if (StringUtil::startsWith($renderer, 'renderFloat') || StringUtil::startsWith($renderer, 'renderPercents')) {
            return BaseList::TYPE_FLOAT;
        }

        return BaseList::TYPE_STRING;
    }
}
