<?php

namespace Teknisa\Libs\Util;

use Zeedhi\Framework\DTO;
use Zeedhi\Framework\DataSource\DataSet;
use Teknisa\Libs\Util\Messages;
use Teknisa\Libs\Util\Utilities as LibUtilities;

class ReportDecorator {
    
    const BIRT_PATH_PARAMETER = 'birtReportPath'; 
    const QR2_PATH_PARAMETER  = 'qr2ReportPath';
    const NRORG_PARAMETER     = 'LOGIN_ORGANIZATION_ID';
    
    const BIRT_EXTENSION = 'RPTDESIGN';
    const QR2_EXTENSION  = 'QR2';
    const STRATEGY_EXTENSION = [
        'RPTDESIGN' => 'BIRT',
        'QR2'       => 'QR2',
    ];
    
    protected $container;
    protected $nrorg;
    protected $windowPrefix;
    protected $errors;
    
    protected $qr2Path;
    protected $birtPath;
    
    public function __construct($environment) {
        $this->container = \Zeedhi\Framework\DependencyInjection\InstanceManager::getInstance()->getContainer();
        $this->nrorg = $environment->getNrorgTrab() != null ? $environment->getNrorgTrab(): $environment->getNrorg();
        $this->errors = [];

        if ($this->nrorg === 1 || !$this->nrorg) {
            $this->nrorg = LibUtilities::readOAccCustom();
            $this->nrorg = $this->nrorg ?? 1;
            if ($this->nrorg === 1 && $this->container->hasParameter(self::NRORG_PARAMETER) && $this->container->getParameter(self::NRORG_PARAMETER) != null) {
                $this->nrorg = $this->container->getParameter(self::NRORG_PARAMETER);
            }
        }

        if ($this->container->hasParameter(self::BIRT_PATH_PARAMETER) && $this->container->getParameter(self::BIRT_PATH_PARAMETER) != null) {
            $this->birtPath = $this->standardizeBirtReportPath($this->container->getParameter(self::BIRT_PATH_PARAMETER)) ;
        }
        
        if ($this->container->hasParameter(self::QR2_PATH_PARAMETER) && $this->container->getParameter(self::QR2_PATH_PARAMETER) != null) {
            $this->qr2Path = $this->container->getParameter(self::QR2_PATH_PARAMETER);
        }
    }
    
    public function standardizeBirtReportPath($birtPath)
    {
        $urlCompleta = getcwd();
        $birtReportPathArray = explode('/', $birtPath);
        
        $splitCharacter = array_filter($birtReportPathArray, function ($folder) use ($urlCompleta) {
            if (empty($folder)) return false;

            return strpos($urlCompleta, $folder) !== false;
        });

        $splitCharacter = array_shift($splitCharacter);
	    $paths = explode($splitCharacter , $urlCompleta);
	    $commonPath = array_shift($paths);
        
        $newPath = $commonPath . $birtPath;

        if (strpos($newPath, "//") !== false) {
            $newPath =  str_replace("//", "/", $newPath);
        }
        
        return $newPath;
    }

    public function getData(DTO\Request\Row $request, DTO\Response $response) {
        $row = $request->getRow();
        $this->windowPrefix = $row[0];
        
        $qr2Reports    = array();
        $qr2Especifico = array();
        $birtReports   = array();
        $reportData    = array();
        
        try {
            $qr2Especifico = array_merge($this->getQr2Reports(true), $qr2Reports);
        } catch (\Exception $e) {
            array_push($this->errors, $e->getMessage());
        }
        
        try {
            $qr2Reports = array_merge($this->getQr2Reports(), $qr2Reports);
        } catch (\Exception $e) {
            array_push($this->errors, $e->getMessage());
        }
        
        try {
            $birtReports = array_merge($this->getBirtReports(), $birtReports);
        } catch (\Exception $e) {
            array_push($this->errors, $e->getMessage());
        }
        
        if (!empty($qr2Especifico)) {
            $reportData = array_merge($reportData, $this->buildData($qr2Especifico, $this->qr2Path,   self::QR2_EXTENSION));
        } else {
            if (!empty($qr2Reports)) {
                $reportData = array_merge($reportData, $this->buildData($qr2Reports, $this->qr2Path,   self::QR2_EXTENSION));
            }
        }
        
        if (!empty($birtReports)) {
            $reportData = array_merge($reportData, $this->buildData($birtReports, $this->birtPath, self::BIRT_EXTENSION));
        }
        
        if (!empty($this->errors)) {
            $reportData[] = $this->errors;
        }

        $response->setDataSets(array(new DataSet('dataReport', $reportData)));
    }
    
    private function getQr2Reports($especifico = false) {
        if (empty($this->qr2Path)) {
            throw new \Exception('Servidor de relatórios QR2 não está parametrizado.', 500);
        }
        
        return $this->getQRDReportsMatched($especifico);
    }
    
    private function getBirtReports() {
        if (empty($this->birtPath)) {
            throw new \Exception('Servidor de relatórios BIRT não está parametrizado.', 500);
        }
        
        return $this->getReportsMatched($this->birtPath, self::BIRT_EXTENSION, Messages::ERR_GET_BIRTPATH_REPORTS_TO_BUILD_LIST);
    }
    
    private function buildData($reportList, $baseDir, $extension) {
        $data = array();
        
        foreach ($reportList as $report) {
            $options = $this->getOptions($extension, $report, $baseDir);
            $reportDescription = $this->getReportDescription($extension, $options);
            
            if ($reportDescription) {
                $reportDescription = self::sanitizeReportDescription($reportDescription);
                
                $data[] = array(
                    'value' => $this->getValueField($extension, $options),
                    'description' => $reportDescription." - ".self::STRATEGY_EXTENSION[$extension],
                    'strategy' => self::STRATEGY_EXTENSION[$extension]
                ); 
            }
        }
        
        return $data;
    }
    
    private function getOptions($extension, $report, $baseDir = '')
    {
        if ($extension == self::QR2_EXTENSION) {
            return $this->getQRDCodeAndDescription($report);
        }
        
        $fileDir = $baseDir . DIRECTORY_SEPARATOR . $report;
        
        return [
            'CODE'     => $report,
            'FILE_DIR' => $fileDir,
        ];
    }
    
    private function getReportDescription($extension, $options)
    {
        switch ($extension) {
            case self::QR2_EXTENSION:
                return $options['DESCRIPTION'];
            case self::BIRT_EXTENSION:
                $fileString = file_get_contents($options['FILE_DIR']);
                $title = '';
                $domResult = new \DOMDocument("1.0", "UTF-8");
                $domResult->loadXML($fileString);
                
                $properties = $domResult->getElementsByTagName("text-property");
                
                if (!empty($properties)) {
                    $propertie = $properties[0];
                    
                    if (isset($propertie->attributes[0])) {
                        if ($propertie->attributes[0]->value == 'title') {
                            $title = $propertie->nodeValue;
                        }
                    }
                }
                
                return $title;
            default:
                throw \Exception('Extensão não suportada.', 500);
        }
    }
    
    private function getValueField($extension, $options)
    {
        if ($extension == self::QR2_EXTENSION) {
            $code = $options['CODE'];
        } else {
            $code = explode("." , $options['CODE'])[0];
        }
        
        
        return $code . '.' . self::STRATEGY_EXTENSION[$extension];
    }
    
    /**
     * O nome Filial deverá ser substituído por Unidade.
     * 
     * @param string $reportNameChange recebe o nome do Relatorio a ser substituído o nome Filial para Unidade
     * 
     * @return string o nome do relatorio alterado
     */
    private function sanitizeReportDescription($reportNameChange)
    {
        $reportNameChange = explode(" ", $reportNameChange) ;
      
        foreach ($reportNameChange as $key => &$value) {
            $value = mb_strtoupper($value) == "FILIAL" ? "Unidade" : $value;
        }
        
        $reportNameChange = implode(" ", $reportNameChange);
        
        return $reportNameChange;
    }
    
    private function getReportsMatched($dirToScan, $extension, $errorMess)
    {
        if (is_dir($dirToScan)) {
            $reportList = scandir($dirToScan);
    
            if ($reportList != false) {
                $dirNrorg = "$dirToScan".DIRECTORY_SEPARATOR."/$this->nrorg";
                
                $reports =  array_filter($reportList, function($report) use (&$extension) {
                    return $this->matchReport($report, $extension);
                });
                
                if (is_dir($dirNrorg)) {
                    $reportListNrorg = scandir($dirNrorg);

                    $reportsNrorg = array_filter($reportListNrorg, function($report) use (&$extension) {
                        return $this->matchReport($report, $extension);
                    });
                    
                    foreach($reportsNrorg as &$report) {
                        $report = $this->nrorg.DIRECTORY_SEPARATOR.$report;
                    }
                    
                    $reports = array_merge($reports, $reportsNrorg);
                    
                }
                
                return $reports;
            } else {
                throw new \Exception($errorMess, 1);
            }
        } else {
            throw new \Exception("$dirToScan não é um diretório.", 1);
        }
    }
    
    private function matchReport($report, $extension)
    {
        $regex = "/^(?i)$this->windowPrefix/";

        $resultMatch = preg_match($regex, $report);
        if ($resultMatch != 0) {
            return strpos(strtoupper($report), $extension) !== false;
        } else {
            return false;
        }
    }
    
    private function getCOMMethod($firstAttempt = true, $especifico = false) {
        if($firstAttempt) {
            $baseUrl = $this->qr2Path;
        } else {
            $baseUrl = \Zeedhi\Framework\DependencyInjection\InstanceManager::getInstance()->getParameter('aspUrl');
        }
        
        $serviceWSDL = '/comwebservice/service.asmx?wsdl';
        $url = $baseUrl . $serviceWSDL;
        $options = array(
            'trace'       => true,
            'exceptions'  => true,
            'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
        );
        
        if($especifico){
            $args = array(
                new \SoapVar($this->windowPrefix, XSD_STRING, 'string', "http://www.w3.org/2001/XMLSchema"),
                new \SoapVar($this->nrorg, XSD_STRING, 'string', "http://www.w3.org/2001/XMLSchema"),
            );
        }else{
            $args = array(
                new \SoapVar($this->windowPrefix, XSD_STRING, 'string', "http://www.w3.org/2001/XMLSchema"),
            );
        }

        $params = array(
            'rdm'    => 'QRD.rdmQRDesign',
            'method' => 'GetReports',
            'args'   => $args,
        );

        try {
            $client = new \SoapClient($url, $options);
            $result = $client->executeCOMMethod($params)->executeCOMMethodResult;
        } catch (\SoapFault $e) {
            if($firstAttempt) {
                $result = self::getCOMMethod(false, $especifico);
            } else {
                throw new \Exception($e->getMessage(), 500);
            }
        }

        return $result;
    }
    
    private function getQRDReportsMatched($especifico = false) {
        return $this->prepareQRDReports(self::getCOMMethod(true, $especifico), $especifico);
    }
    
    private function prepareQRDReports($result, $especifico = false) {
        $reports = [];
        $resultArray = explode("\n", $result);
        
        foreach ($resultArray as $key => $report) {
            if ($key == 0 || empty($report)) continue; // Skip FTP infos and empty data
            
            array_push($reports, $report);
        }
        
        if (empty($reports) && !$especifico) {
            throw new \Exception('Não há relatórios QR2 para montagem da lista de relatórios.', 500);
        }
        
        return $reports;
    }
    
    private function getQRDCodeAndDescription($relatorio)
    {
        $relData = explode("=", $relatorio);
        $suffix  = $relData[0];
        $title   = $relData[1];
        
        return [
            'CODE'        => $this->windowPrefix . $suffix,
            'DESCRIPTION' => substr($title, 14), // Skip timestamp on title
        ];
    }
}