<?php

namespace Drupal\basket;

use Drupal\Core\Url;
use Drupal\views\Views;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Drupal\Core\Render\Markup;

class BasketExport{
    public static function run($subType = NULL){
        if(!class_exists(Spreadsheet::class)){
            return \Drupal::service('Basket')->getError(404);
        }
        if(!\Drupal::currentUser()->hasPermission('basket access_export_order')){
            return \Drupal::service('Basket')->getError(403);
        }
        $request = \Drupal::request()->query->all();
        switch($subType){
            case'finish':
                if(!empty($request['download'])){
                    self::downloadExcel();
                    exit;
                }
                $downloadUrl = Url::fromRoute('basket.admin.pages', ['page_type' => 'orders-export-finish'],['query' => ['download' => 1]])->toString();
                return [
                    '#prefix'       => '<div class="basket_table_wrap" id="export_finish">',
                    '#suffix'       => '</div>',
                    [
                        '#prefix'       => '<div class="b_title">',
                        '#suffix'       => '</div>',
                        '#markup'       => \Drupal::service('Basket')->Translate()->t('Export orders'),
                    ],[
                        '#prefix'       => '<div class="b_content">',
                        '#suffix'       => '</div>',
                        '#type'         => 'inline_template',
                        '#template'     => '<b>{{ title }}</b><br/>{{ text }}',
                        '#context'      => [
                            'title'         => \Drupal::service('Basket')->Translate()->t('Export completed successfully.'),
                            'text'          => \Drupal::service('Basket')->Translate()->t('If the automatic download has not started - click on the @link@.', [
                                '@link@'        => Markup::create('<a href="'.$downloadUrl.'">'.\Drupal::service('Basket')->Translate()->t('link').'</a>')
                            ])
                        ],[
                            '#type'         => 'inline_template',
                            '#template'     => '<br/><a href="javascript:void(0);" onclick="self.close()" class="download">{{text}}</a>',
                            '#context'      => [
                                'text'          => \Drupal::service('Basket')->Translate()->t('Close page')
                            ]
                        ]
                    ],[
                        '#markup'       => Markup::create('<script type="text/javascript">window.location.href="'.$downloadUrl.'";</script>')
                    ]
                ];
            break;
            default:
                self::dataInfo('clear');
                $operations = [];
                if(!empty(Views::getEnabledViews()['basket'])){
                    if(!empty($export_fields = \Drupal::request()->query->get('export_fields'))){
                        \Drupal::request()->query->set('fields', $export_fields);
                    }
                    $view = Views::getView('basket');
                    $view->setItemsPerPage(0);
                    $view->execute('block_1');
                    if(!empty($view->result)){
                        foreach ($view->result as $row){
                            if(empty($row->basket_orders_id)) continue;
                            $operations[] = ['\\'.__CLASS__.'::process', [$row->basket_orders_id]];
                        }
                    }
                }
                if(!empty($operations)){
                    $batch = array(
                        'title'             => \Drupal::service('Basket')->Translate()->t('Export orders'),
                        'operations'        => $operations,
                        'basket_batch'      => TRUE
                    );
                    batch_set($batch);
                    $response = batch_process(Url::fromRoute('basket.admin.pages', ['page_type' => 'orders-export-finish'])->toString());
                    $response->send();
                } else {
                    return \Drupal::service('Basket')->getError(404);
                }
            break;
        }
    }
    public static function process($orderId, &$context){
        $Basket = \Drupal::service('Basket');
        $Order = $Basket->Orders($orderId)->load();
        $data = [
            'lines'     => [],
            'color'     => NULL
        ];
        $context = [];
        foreach (self::getTokenInfo() as $keyTwig => $tokenTwig) {
            $context[$keyTwig] = $Basket->Token()->getToken($keyTwig, [
                'order'     => $Order
            ]);
        }
        $config = $Basket->getSettings('export_orders', 'config');
        $OrderNode = NULL;
        if(!empty($Order->nid)){
            $OrderNode = \Drupal\node\Entity\Node::load($Order->nid);
        }
        if(empty($Order->items)) $Order->items = [[]];
        $lineKey = 0;
        foreach ($Order->items as $row){
            if(!empty($lineKey)){
                $OrderNode = NULL;
                $context = [];
            }
            foreach (self::getTokenInfo() as $keyTwig => $tokenTwig){
                if(empty($tokenTwig['lineAll'])) continue;
                $context[$keyTwig] = $Basket->Token()->getToken($keyTwig.'.'.$row->id, [
                    'orderItem'     => $row,
                    'order'         => $Order
                ]);
            }
            $data['lines'][$lineKey] = [];
            foreach ($config['orders']['data'] as $letter => $tokenText){
                $data['lines'][$lineKey][$letter] = !empty($tokenText) ? trim($tokenText) : '';
                if(!empty(trim($tokenText))){
                    $tokenText = [
                        '#type'     => 'inline_template',
                        '#template' => $tokenText,
                        '#context'  => $context
                    ];
                    $data['lines'][$lineKey][$letter] = \Drupal::token()->replace(
                        \Drupal::service('renderer')->render($tokenText), [
                            'user'      => !empty($OrderNode) ? \Drupal\user\Entity\User::load($OrderNode->get('uid')->target_id) : NULL,
                            'node'      => $OrderNode
                        ], [
                            'clear'     => TRUE
                        ]
                    );
                } else {
                    $data['lines'][$lineKey][$letter] = NULL;
                }
            }
            $lineKey++;
        }
        if(!empty($data['lines'])){
            \Drupal::database()->insert('basket_orders_export')
                ->fields([
                    'uid'       => \Drupal::currentUser()->id(),
                    'data'      => serialize($data)
                ])
                ->execute();
        }
    }
    public static function getTokenInfo(){
        $info = drupal_get_path('module', 'basket').'/config/basket_install/TwigExcelTokens.yml';
        $tokens = \Drupal\Component\Serialization\Yaml::decode(file_get_contents($info));
        // Alter
        $templateType = 'orders_export';
        \Drupal::moduleHandler()->alter('basketTemplateTokens', $tokens, $templateType);
        // ---
        return $tokens;
    }
    public static function dataInfo($type){
        switch($type){
            case'clear':
                \Drupal::database()->delete('basket_orders_export')
                            ->condition('uid', \Drupal::currentUser()->id())
                            ->execute();
            break;
            case'load':
                return \Drupal::database()->select('basket_orders_export', 'f')
                                    ->fields('f', ['data'])
                                    ->condition('f.uid', \Drupal::currentUser()->id())
                                    ->orderBy('f.id', 'ASC')
                                    ->execute()->fetchCol();
            break;
        }
    }
    public static function getLinkOrderExport($orderId){
        $context = self::getLinkOrderExportContext($orderId);
        if(empty($context)) return [];
        return [
            '#type'         => 'inline_template',
            '#template'     => '<a href="{{ url }}" target="_blank" class="button--link"><span class="ico">{{ ico|raw }}</span> {{ text }}</a>',
            '#context'      => self::getLinkOrderExportContext($orderId)
        ];
    }
    public static function getLinkOrderExportContext($orderId){
        if(!\Drupal::currentUser()->hasPermission('basket access_export_order')) return [];
        $Order = \Drupal::service('Basket')->Orders($orderId)->load();
        if(empty($Order->id) || !is_numeric($Order->id)) return [];
        if(!class_exists(Spreadsheet::class)) return [];
        if(!empty($Order->is_delete)) return [];
        return [
            'text'          => \Drupal::service('Basket')->Translate()->t('Export'),
            'ico'           => \Drupal::service('Basket')->getIco('export.svg'),
            'url'           => Url::fromRoute('basket.admin.pages', [
                'page_type'     => 'orders-export'
            ],[
                'query'         => [
                    'export_fields' => ['id' => $orderId]
                ]
            ])->toString(),
            'target'        => '_blank'
        ];
    }
    private static function downloadExcel(){
        $Basket = \Drupal::service('Basket');
        $config = $Basket->getSettings('export_orders', 'config');
        $filename = $Basket->Translate()->t('Orders').' ('.date('d.m.Y H:i').').xlsx';
        $file_path = \Drupal::service('file_system')->getTempDirectory().'/'.$filename;
        /*Spreadsheet*/
        $spreadsheet = new Spreadsheet();
        $spreadsheet->getActiveSheet()->getPageSetup()->setRowsToRepeatAtTopByStartAndEnd(1, 1);
        $sheet = $spreadsheet->getActiveSheet();
        /*Header*/
        $headerNum = 1;
        foreach ($config['orders']['header'] as $letter => $text){
            if(empty(trim($text))) continue;
            $sheet->setCellValue($letter.''.$headerNum, $Basket->Translate()->t(trim($text)));
        }
        // Fixed header
        $sheet->freezePane('A2');
        /*Rows*/
        $rowsNum = $rowsNumStart = $headerNum+1;
        $rows = self::dataInfo('load');
        $RowBorders = [];
        if(!empty($rows)){
            foreach ($rows as $row){
                $row = unserialize($row);
                if(empty($row['lines'])) continue;
                foreach ($row['lines'] as $line){
                    foreach ($line as $letter => $setValue){
                        if(empty(trim($setValue)))  continue;
                        $sheet->setCellValueExplicit($letter.''.$rowsNum, $setValue, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
                    }
                    $rowsNum++;
                }
                $RowBorders[($rowsNum-1)] = ($rowsNum-1);
            }
        }
        /*Colors*/
        $HighestColumn = $sheet->getHighestColumn();
            /*-- Header --*/
            $spreadsheet->getActiveSheet()->getStyle('A'.$headerNum.':'.$HighestColumn.''.$headerNum)->applyFromArray([
                'font' => [
                    'bold' => true,
                ],
                'fill'      => [
                    'fillType'  => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 
                    'color'     => [
                        'rgb'       => '0569CC'
                    ]
                ],
                'borders' => [
                    'allBorders' => [
                        'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                        'color' => ['argb' => '000000'],
                    ],
                ],
            ]);
            $spreadsheet->getActiveSheet()->getStyle('A'.$headerNum.':'.$HighestColumn.''.$headerNum)->getFont()->getColor()->setARGB('ffffff');
            /*-- Rows --*/
            if(!empty($RowBorders)){
                foreach ($RowBorders as $RowBorderNum){
                    $spreadsheet->getActiveSheet()->getStyle('A'.$RowBorderNum.':'.$HighestColumn.''.$RowBorderNum)->applyFromArray([
                        'borders' => [
                            'bottom' => [
                                'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUM,
                                'color' => ['argb' => '000000'],
                            ],
                        ],
                    ]);
                }
            }
        $spreadsheet->getActiveSheet()->getStyle('A'.($headerNum+1).':'.$HighestColumn.''.$rowsNum)->getAlignment()->setWrapText(true);
        /*Auto width*/
        foreach (range('A', $HighestColumn) as $letter){
            $spreadsheet->getActiveSheet()->getColumnDimension($letter)->setAutoSize(true);
        }
        /*Save*/
        $writer = new Xlsx($spreadsheet);
        $writer->save($file_path);
        /*Download*/
        $response = new BinaryFileResponse($file_path, 200, [], FALSE, 'attachment');
        $response->deleteFileAfterSend(TRUE);
        $response->send();
    }
}