<?php

namespace App\Providers\ExcelGroupUnitaryReport;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class ExcelGroupUnitaryReport {

    protected function markTypeRoomColspan ($passengers) {
        return array_reduce ($passengers, function ($carry, $passenger) {
            
            $found = $this->findTypeRoomCarry ($carry, $passenger->Id_Room );

            if (count ($found)) {
                $found[0]->Current_Count++;
                $carry[] = $passenger;
            } else {
                $carry[] = $this->convertToRoomCarry ($passenger);
            }
            return $carry;
        }, []);
    }

    protected function convertToRoomCarry ($passenger) {
        $passenger->Current_TypeRoom = $passenger->Id_Room;
        $passenger->Current_Count = 0;
        return $passenger;
    }

    protected function findTypeRoomCarry ($target, $id):array {
        return array_values (array_filter ($target, function ($ele) use ($id) { return isset ($ele->Current_TypeRoom) && $ele->Current_TypeRoom == $id; }));
    }

    public function exportToExcel($data, $Date) {

        $_ = $this;
        $data = array_map ( 
            function ($row) use ($_) {
                
		        foreach ($row->Group_Slaves as $slaves) {
                    $slaves->Passenger=$_->markTypeRoomColspan($slaves->Passenger);
                }
                $row->Passenger = $_->markTypeRoomColspan($row->Passenger);
                return $row;
            },
            $data
        );
        

        $page = new ExcelPage();
        $usuario = 'auasd';

        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        $title = 'ORDEN DE SALIDA ' . date ('d-m-Y', strtotime ($Date));

        $this->render (
            $sheet,
            $data,
            (object)[
                'Title' => $title
            ]
        );

        $writer = IOFactory::createWriter($spreadsheet, "Xlsx");
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment; filename="' . $title . '.xlsx"');
        $writer->save("php://output");
    }

    public function render (Worksheet $sheet, $tours, $data) {
        
        $currentRow = 0;
        foreach ($tours as $tour) {
            
            $this->renderPage ($sheet, new ExcelPage(), $tour, $currentRow, $data);
            $this->renderAllInOnePage ($sheet, new PrintPage(), $tour, $currentRow, $data);
            $this->renderAllInOnePage ($sheet, new PassengerPage(), $tour, $currentRow, $data);
            $this->renderPage ($sheet, new ColumnsWidthExcel(), $tour, $currentRow, $data);
            $this->renderPage ($sheet, new PassengerCells(), $tour, $currentRow, $data);
            $this->renderAllInOnePage ($sheet, new PassengerStyle(), $tour, $currentRow, $data);
            
            $currentRow += $this->evaluateRowLength($tour);
        }
        
    }

    public function evaluateRowLength ($tour) {
        $paddingTop = 12;
        $marginBottom = 3;
        return $paddingTop + count($tour->Passenger) + $marginBottom;
    }

    public function renderPage (Worksheet $sheet, ExcelPage $page, $tour, $initialRow, $data) {
        $letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        foreach ($page->run($tour, $data) as $ind => $row) {
            $column = 0;
            foreach ($row as $order) {
                switch ($order['action']) {
                    case 'print':
                        $range1 = $letters[$column] . ($initialRow + $ind + 1);
                        $sheet->setCellValue("$range1", $order['text']);
                        break;
                    
                    case '': break;
                    case 'merge':
                        $range1 = $letters[$column] . ($initialRow + $ind + 1);
                        $range2 = $letters[$column + $order['lines']] . ($initialRow + $ind + 1);
                        $sheet->mergeCells("$range1:$range2");
                        $column += $order['lines'];
                        break;
                    case 'advance':
                        $column += $order['lines'];
                        break;
                    case 'width':
                        $sheet->getColumnDimensionByColumn($column + 1)->setWidth($order['width']);
                        break;
                    case 'border':
                        $sheet->getStyle($letters[$column] . ($initialRow + $ind + 1))
                        ->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
                }
                $column++;
            }
            
        }
    }

    public function renderAllInOnePage (Worksheet $sheet, $page, $tour, $initialRow, $data) {
        $letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        foreach ($page->run($tour, $data) as $ind => $row) {
            $column = 0;
            $currentRow = ($initialRow + $ind + 1);
            foreach ($row as $orders) {
                foreach ($orders as $order) {
                    switch ($order['action']) {
                        case 'print': $column = $this->print($sheet, $order, $column, $currentRow); break;
                        
                        case '': $column = $this->pass($sheet, $order, $column, $currentRow); break;
                        case 'merge': $column = $this->merge($sheet, $order, $column, $currentRow); break;
                        case 'vmerge': $column = $this->vmerge($sheet, $order, $column, $currentRow); break;
                        case 'advance': $column = $this->advance($sheet, $order, $column, $currentRow); break;
                        case 'width': $column = $this->width($sheet, $order, $column, $currentRow); break;
                        case 'border': $column = $this->border($sheet, $order, $column, $currentRow); break;
                        case 'bold': $column = $this->bold($sheet, $order, $column, $currentRow); break;
                        case 'center': $column = $this->center($sheet, $order, $column, $currentRow); break;
                        case 'top': $column = $this->top ($sheet, $order, $column, $currentRow); break;
                        case 'left': $column = $this->left($sheet, $order, $column, $currentRow); break;
                        case 'wrap': $column = $this->wrap ($sheet, $order, $column, $currentRow); break;
                        case 'size': $column = $this->size ($sheet, $order, $column, $currentRow); break;
                    }
                }
                $column++;
            }
            
        }
    }

    public const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

    protected function print($sheet, $order, $column, $currentRow) {
        $range1 = self::letters[$column] . $currentRow;
        $sheet->setCellValue("$range1", $order['text']);
        return $column;
    }
    protected function pass ($sheet, $order, $column, $currentRow) { return $column; }

    protected function merge ($sheet, $order, $column, $currentRow) {
        $range1 = self::letters[$column] . $currentRow;
        $range2 = self::letters[$column + $order['lines']] . $currentRow;
        $sheet->mergeCells("$range1:$range2");
        $column += $order['lines'];
        return $column;
    }
    protected function size ($sheet, $order, $column, $currentRow) {
        
        $sheet->getStyle(self::letters[$column] . $currentRow)->getFont()->setSize($order['lines']);
        return $column;
    }
    protected function vmerge ($sheet, $order, $column, $currentRow) {
        $range1 = self::letters[$column] . $currentRow;
        $range2 = self::letters[$column] . ($currentRow - (-$order['lines']));
        $sheet->mergeCells("$range1:$range2");
        return $column;
    }

    protected function advance ($sheet, $order, $column, $currentRow) {
        $column += $order['lines'];
        return $column;
    }

    protected function width ($sheet, $order, $column, $currentRow) {
        $sheet->getColumnDimensionByColumn($column + 1)->setWidth($order['width']);
        return $column;
    }

    protected function border ($sheet, $order, $column, $currentRow) {
        $sheet->getStyle(self::letters[$column] . $currentRow)
            ->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
        return $column;
    }

    protected function bold ($sheet, $order, $column, $currentRow) {
        $sheet->getStyle(self::letters[$column] . $currentRow)->getFont()->setBold(true); 
        return $column;
    }

    protected function center ($sheet, $order, $column, $currentRow) {
        $sheet ->getStyle(self::letters[$column] . $currentRow)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
        return $column;
    }

    protected function left ($sheet, $order, $column, $currentRow) {
        $sheet->getStyle(self::letters[$column] . $currentRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT);
        return $column;
    }

    protected function top ($sheet, $order, $column, $currentRow) {
        $sheet->getStyle(self::letters[$column] . $currentRow)->getAlignment()->setVertical(Alignment::VERTICAL_TOP);
        return $column;
    }

    protected function wrap ($sheet, $order, $column, $currentRow) {
        $sheet->getStyle(self::letters[$column] . $currentRow)->getAlignment()->setWrapText(true);
        return $column;
    }

}