<?php

namespace App\Modules\Invoice\Actions;

use App\Modules\Excell\Excell;
use App\Modules\Excell\Fonts\FONTS;
use App\Modules\Excell\Types\iRichText\RichTextWrapper;
use App\Modules\Invoice\Data\InvoiceExcellData;
use App\Modules\Invoice\Data\InvoiceItem;
use App\Modules\Makeable;
use App\Modules\TurkmenNumberFormatter\Repositories\TurkmenNumberFormatter;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class GenerateInvoiceExcell
{
    use Makeable;

    /** Template file */
    protected string $templateFile;

    /** Excell Spreadsheet */
    protected Spreadsheet $spreadsheet;

    /** Active worksheet */
    protected Worksheet $worksheet;

    /** Invoice data */
    protected InvoiceExcellData $data;

    /**
     * Let's generate an invoice excell file...
     */
    public function __construct()
    {
        // For turkmen date format...
        Carbon::setLocale('tk');
    }

    /**
     * Run conversion process
     */
    public function handle(): self
    {
        $this->setSpreadsheetFile();
        $this->setWorksheetFile();
        $this->fillTheCells();

        return $this;
    }

    /**
     * Save the invoice
     */
    public function save(): void
    {
        $writer = IOFactory::createWriter($this->spreadsheet, 'Xls');

        $writer->save('write.xls');
    }

    /**
     * Set template file path
     */
    public function setTemplateFile(string $file): self
    {
        $this->templateFile = $file;

        return $this;
    }

    /**
     * Set data
     */
    public function setData(InvoiceExcellData $data): self
    {
        $this->data = $data;

        return $this;
    }

    /**
     * Load template to a new spreadsheet
     */
    protected function setSpreadsheetFile(): void
    {
        $this->spreadsheet = IOFactory::load($this->templateFile);
    }

    /**
     * Set working spreadsheet
     */
    protected function setWorksheetFile(): void
    {
        $this->worksheet = $this->spreadsheet->getActiveSheet();
    }

    /**
     * Return new RichTextWrapper
     */
    public function richText(): RichTextWrapper
    {
        return Excell::richText()
            ->setDefaultFont(FONTS::TIMES_NEW_ROMAN)
            ->setDefaultSize(10);
    }

    /**
     * Fill the cells
     */
    protected function fillTheCells(): void
    {
        $data = $this->getTemplateValues();

        foreach ($data as $cell => $value) {
            $this->worksheet->getCell($cell)->setValue($value);
        }

        $this->fillItems();
    }

    /**
     * Get template cells and values
     *
     * @return array<string, mixed>
     */
    protected function getTemplateValues(): array
    {
        return [
            'C6' => $this->hasapFakturaNomeri(),
            'C7' => $this->sene(),
            'A9' => $this->satyjy(),
            'A11' => $this->satyjySalgytBelgi(),
            'A12' => $this->satyjyBanky(),
            'A13' => $this->satyjyBankyMaglumatlary(),
            'A16' => $this->satynAlyjy(),
            'A18' => $this->satynAlyjySalgy(),
            'A19' => $this->satynAlyjyBanky(),
            'A20' => $this->satynAlyjyBankyMaglumatlary(),
        ];
    }

    /**
     * Hasap faktura nomeri
     */
    public function hasapFakturaNomeri(): string
    {
        return 'Hasap-faktura № '.$this->data->number;
    }

    /**
     * Sene
     */
    public function sene(): string
    {
        $date = $this->data->date;

        $year = $date->year;
        $day = $date->format('d');
        $month_as_string = $date->translatedFormat('F');

        return sprintf('%s ýylyň «%s» %s', $year, $day, $month_as_string);
    }

    /**
     * Satyjy
     */
    public function satyjy(): string
    {
        return sprintf('Satyjy: %s %s', $this->data->seller_firm_type, $this->data->seller_firm_name);
    }

    /**
     * Satyjy salgyt belgisi
     */
    public function satyjySalgytBelgi(): RichText
    {
        return $this->richText()
            ->add('Satyjynyň şahsy salgyt belgisi: ')
            ->add($this->data->seller_ssb, bold: true)
            ->toRichText();
    }

    /**
     * Satyjy bank maglumatlary
     */
    public function satyjyBanky(): RichText
    {
        return $this->richText()
            ->add(sprintf('Satyjynyň bankynyň ady %s, hasap № ', $this->data->seller_bank_name))
            ->add($this->data->seller_bank_hb_1, bold: true)
            ->toRichText();
    }

    /**
     * Satyjy bank maglumatlary
     */
    public function satyjyBankyMaglumatlary(): RichText
    {
        return $this->richText()
            ->add('şäherde (etrapda) ')
            ->add($this->data->seller_bank_city, bold: true)
            ->add(' BAB ')
            ->add($this->data->seller_bank_bab, bold: true)
            ->add(' bankyň kor.hasap ')
            ->add($this->data->seller_bank_hb_2, bold: true)
            ->toRichText();
    }

    /**
     * Satyn alyjy
     */
    public function satynAlyjy(): string
    {
        return 'Satyn alyjy: '.$this->data->buyer;
    }

    /**
     * Satyn alyjy salgy
     */
    public function satynAlyjySalgy(): string
    {
        return $this->data->buyer_address;
    }

    /**
     * Satyn alyjy banky we salgysy
     */
    public function satynAlyjyBanky(): string
    {
        return sprintf('Alyjynyň bankynyň ady %s %s', $this->data->buyer_bank, $this->data->buyer_bank_address);
    }

    /**
     * Satyn alyjynyň bank maglumatlary
     */
    public function satynAlyjyBankyMaglumatlary(): string
    {
        return 'Satyn alyjynyň '.$this->data->buyer_bank_data;
    }

    /**
     * Default cell styles
     *
     * @return array<string, array<string, array<string, string>|bool|int|string>>
     */
    public function defaultCellStyles(): array
    {
        return [
            'font' => [
                'bold' => false,
                'size' => 10,
                'name' => 'Times New Roman',
            ],
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER,
                'vertical' => Alignment::VERTICAL_CENTER,
            ],
            'borders' => [
                'allBorders' => [
                    'borderStyle' => Border::BORDER_THIN,
                ],
            ],
        ];
    }

    /**
     * Cell bold style
     *
     * @return array<string, array<string, string|bool|int>>
     */
    public function cellStyleBold(): array
    {
        return [
            'font' => [
                'bold' => true,
            ],
        ];
    }

    /**
     * Cell style center
     *
     * @return array<string, array<string, string>>
     */
    public function cellStyleCenter(): array
    {
        return [
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_LEFT,
                'vertical' => Alignment::VERTICAL_CENTER,
            ],
        ];
    }

    /**
     * Fill items
     */
    public function fillItems(): void
    {
        $items = collect($this->data->items);

        $total = 0;
        $itemCellNumber = 25;
        $numberFormat = '#,##0.00';
        $items->each(function (InvoiceItem $item, int $index) use (&$itemCellNumber, &$total, $numberFormat) {
            $this->worksheet->getCell('A'.$itemCellNumber)->setValue($index + 1);
            $this->worksheet->getCell('B'.$itemCellNumber)->setValue($item->name);
            $this->worksheet->getCell('C'.$itemCellNumber)->setValue($item->unit);
            $this->worksheet->getCell('D'.$itemCellNumber)->setValue($item->quantity);
            $this->worksheet->getCell('E'.$itemCellNumber)->setValue($item->unit_price);
            $this->worksheet->getCell('F'.$itemCellNumber)->setValue($item->vat);
            $this->worksheet->getCell('G'.$itemCellNumber)->setValue($item->vat_excluded);
            $this->worksheet->getCell('H'.$itemCellNumber)->setValue($item->vat_percentage);
            $this->worksheet->getCell('I'.$itemCellNumber)->setValue($item->vat_tmt);

            $total += ($item->quantity * $item->unit_price);
            $this->worksheet->setCellValue(
                'J'.$itemCellNumber,
                "=D{$itemCellNumber}*E{$itemCellNumber}"
            );

            // Set font-family, alingment, and borders for all of them...
            $this->worksheet->getStyle('A'.$itemCellNumber.':J'.$itemCellNumber)->applyFromArray($this->defaultCellStyles());

            // Invoice Name...
            $this->worksheet->getCell('B'.$itemCellNumber)->getStyle()->applyFromArray($this->cellStyleCenter());

            // Bold cells...
            $this->worksheet->getCell('D'.$itemCellNumber)->getStyle()->applyFromArray($this->cellStyleBold());
            $this->worksheet->getCell('E'.$itemCellNumber)->getStyle()->applyFromArray($this->cellStyleBold());
            $this->worksheet->getCell('J'.$itemCellNumber)->getStyle()->applyFromArray($this->cellStyleBold());

            // Invoice number format...
            $this->worksheet->getStyle('E'.$itemCellNumber)->getNumberFormat()->setFormatCode($numberFormat);
            $this->worksheet->getStyle('J'.$itemCellNumber)->getNumberFormat()->setFormatCode($numberFormat);

            $itemCellNumber++;
        });

        // Set default styles...
        $this->worksheet->getStyle('A'.$itemCellNumber.':J'.$itemCellNumber)->applyFromArray($this->defaultCellStyles());

        $this->worksheet->getCell('B'.$itemCellNumber)->setValue('Jemi tölenmeli:')->getStyle()->applyFromArray([
            'font' => ['size' => 11], 'alignment' => ['horizontal' => Alignment::HORIZONTAL_RIGHT],
        ]);

        $lastItemCellNumber = $itemCellNumber - 1;
        $this->worksheet->getCell('J'.$itemCellNumber)->getStyle()->applyFromArray($this->cellStyleBold());
        $this->worksheet->getStyle('J'.$itemCellNumber)->getNumberFormat()->setFormatCode($numberFormat);
        $this->worksheet->setCellValue('J'.$itemCellNumber, "=SUM(J25:J{$lastItemCellNumber})");

        // Next cell..
        $itemCellNumber++;

        $this->worksheet->setCellValue('A'.$itemCellNumber, 'Harydyň (işleriň, hyzmatlaryň) jemi bahasy');
        $this->worksheet->getStyle('A'.$itemCellNumber)->applyFromArray(['font' => ['size' => 9, 'name' => 'Times New Roman']]);

        $this->worksheet->getStyle('C'.$itemCellNumber)->applyFromArray(['font' => ['bold' => true, 'size' => 11, 'name' => 'Times New Roman']]);
        $this->worksheet->setCellValue('C'.$itemCellNumber, Str::ucfirst(TurkmenNumberFormatter::format(floatval($total))));
        $this->worksheet->mergeCells('C'.$itemCellNumber.':J'.$itemCellNumber);

        // Leave empty one
        $itemCellNumber++;
        $itemCellNumber++;

        $this->worksheet->setCellValue('B'.$itemCellNumber, $this->data->seller_firm_name);
        $this->worksheet->getStyle('A'.$itemCellNumber)->applyFromArray(['borders' => ['bottom' => ['borderStyle' => Border::BORDER_THIN]]]);
        $this->worksheet->getStyle('B'.$itemCellNumber)->applyFromArray([
            'font' => ['bold' => true, 'size' => 11, 'name' => 'Times New Roman'],
            'borders' => [
                'bottom' => [
                    'borderStyle' => Border::BORDER_THIN,
                ],
            ],
        ]);

        $this->worksheet->getStyle('G'.$itemCellNumber.':I'.$itemCellNumber)->applyFromArray(['borders' => ['bottom' => ['borderStyle' => Border::BORDER_THIN]]]);
        $itemCellNumber++;

        $this->worksheet->setCellValue('A'.$itemCellNumber, '(görnüşli tarapyň ýolbaşçysynyň ýa-da hususy telekeçiniň F.A.A.A.)');
        $this->worksheet->setCellValue('H'.$itemCellNumber, '(goly)');

        $this->worksheet->getStyle('A'.$itemCellNumber)->applyFromArray(['font' => ['bold' => false, 'size' => 9, 'name' => 'Times New Roman']]);
        $this->worksheet->getStyle('H'.$itemCellNumber)->applyFromArray(['font' => ['bold' => false, 'size' => 9, 'name' => 'Times New Roman']]);

        $itemCellNumber++;
        $itemCellNumber++;
        $itemCellNumber++;
        $itemCellNumber++;

        $this->worksheet->setCellValue(
            'A'.$itemCellNumber,
            sprintf(
                '__________%s____________________________manat_______0________ teňňe möçberde iberilen haryt doly alyndy.',
                Str::before(Str::ucfirst(moneyFormatInTurkmenLetter(floatval($total))), ' manat')
            )
        );

        $this->worksheet->getStyle('A'.$itemCellNumber)->applyFromArray(['font' => ['bold' => false, 'size' => 9, 'name' => 'Times New Roman']]);

        $itemCellNumber++;
        $itemCellNumber++;

        $this->worksheet->setCellValue(
            'A'.$itemCellNumber,
            '_______________________________________________________                             ___________________                           '
        );
        $this->worksheet->getStyle('A'.$itemCellNumber)->applyFromArray(['font' => ['bold' => false, 'size' => 9, 'name' => 'Times New Roman']]);

        $itemCellNumber++;

        $this->worksheet->setCellValue(
            'A'.$itemCellNumber,
            '       Satyn alyjynyň ýa-da kärhananyň ynam bildiren tarapynyň F.A.A A                                                    (goly)'
        );
        $this->worksheet->getStyle('A'.$itemCellNumber)->applyFromArray([
            'font' => ['bold' => false, 'size' => 8, 'name' => 'Times New Roman'],
            'alignment' => ['vertical' => Alignment::VERTICAL_TOP],
        ]);
    }
}
