<?php

declare(strict_types=1);

namespace App\Services;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use Exception;

/**
 * Serviço para Geração e Leitura de Planilhas Excel
 * Utiliza a biblioteca PhpSpreadsheet
 */
class ExcelService
{
    private Spreadsheet $spreadsheet;

    public function __construct()
    {
        $this->spreadsheet = new Spreadsheet();
    }

    /**
     * Exporta dados para Excel
     *
     * @param array $dados Dados a serem exportados
     * @param array $colunas Configuração das colunas
     * @param string $filename Nome do arquivo
     * @param string $output Tipo de saída: download, save, return
     * @return mixed
     */
    public function exportar(array $dados, array $colunas, string $filename = 'exportacao.xlsx', string $output = 'download')
    {
        try {
            $sheet = $this->spreadsheet->getActiveSheet();

            // Título/Cabeçalho
            $colIndex = 1;
            foreach ($colunas as $coluna) {
                $cell = $this->getCellAddress($colIndex, 1);
                $sheet->setCellValue($cell, $coluna['label']);

                // Estilo do cabeçalho
                $sheet->getStyle($cell)->applyFromArray([
                    'font' => [
                        'bold' => true,
                        'color' => ['rgb' => 'FFFFFF'],
                        'size' => 12
                    ],
                    'fill' => [
                        'fillType' => Fill::FILL_SOLID,
                        'startColor' => ['rgb' => '3788d8']
                    ],
                    'alignment' => [
                        'horizontal' => Alignment::HORIZONTAL_CENTER,
                        'vertical' => Alignment::VERTICAL_CENTER
                    ]
                ]);

                // Largura da coluna
                $sheet->getColumnDimension($this->getColumnLetter($colIndex))->setWidth($coluna['width'] ?? 15);

                $colIndex++;
            }

            // Dados
            $rowIndex = 2;
            foreach ($dados as $linha) {
                $colIndex = 1;
                foreach ($colunas as $coluna) {
                    $cell = $this->getCellAddress($colIndex, $rowIndex);
                    $valor = $linha[$coluna['field']] ?? '';

                    // Formata o valor se necessário
                    if (isset($coluna['format'])) {
                        $valor = $this->formatarValor($valor, $coluna['format']);
                    }

                    $sheet->setCellValue($cell, $valor);

                    // Estilo dos dados
                    $sheet->getStyle($cell)->applyFromArray([
                        'borders' => [
                            'allBorders' => [
                                'borderStyle' => Border::BORDER_THIN,
                                'color' => ['rgb' => 'CCCCCC']
                            ]
                        ]
                    ]);

                    $colIndex++;
                }
                $rowIndex++;
            }

            // Retorna conforme solicitado
            if ($output === 'download') {
                return $this->download($filename);
            } elseif ($output === 'save') {
                return $this->salvar($filename);
            } else {
                return $this->spreadsheet;
            }

        } catch (Exception $e) {
            error_log("Erro ao exportar Excel: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Importa dados de um arquivo Excel
     *
     * @param string $filepath Caminho do arquivo
     * @return array Dados importados
     */
    public function importar(string $filepath): array
    {
        try {
            if (!file_exists($filepath)) {
                throw new Exception("Arquivo não encontrado: {$filepath}");
            }

            $spreadsheet = IOFactory::load($filepath);
            $sheet = $spreadsheet->getActiveSheet();

            $highestRow = $sheet->getHighestRow();
            $highestColumn = $sheet->getHighestColumn();
            $highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn);

            // Lê o cabeçalho (primeira linha)
            $headers = [];
            for ($col = 1; $col <= $highestColumnIndex; $col++) {
                $headers[] = $sheet->getCellByColumnAndRow($col, 1)->getValue();
            }

            // Lê os dados
            $dados = [];
            for ($row = 2; $row <= $highestRow; $row++) {
                $linha = [];
                for ($col = 1; $col <= $highestColumnIndex; $col++) {
                    $key = $headers[$col - 1];
                    $linha[$key] = $sheet->getCellByColumnAndRow($col, $row)->getValue();
                }
                $dados[] = $linha;
            }

            return $dados;

        } catch (Exception $e) {
            error_log("Erro ao importar Excel: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Exporta relatório de vendas para Excel
     */
    public function exportarRelatorioVendas(array $vendas, array $filtros = []): void
    {
        $colunas = [
            ['field' => 'numero', 'label' => 'Número', 'width' => 15],
            ['field' => 'data_venda', 'label' => 'Data', 'width' => 15, 'format' => 'date'],
            ['field' => 'cliente_name', 'label' => 'Cliente', 'width' => 30],
            ['field' => 'status', 'label' => 'Status', 'width' => 15],
            ['field' => 'total', 'label' => 'Valor', 'width' => 15, 'format' => 'currency']
        ];

        $this->exportar($vendas, $colunas, 'relatorio-vendas.xlsx', 'download');
    }

    /**
     * Importa produtos de um arquivo Excel
     */
    public function importarProdutos(string $filepath): array
    {
        $dados = $this->importar($filepath);

        // Validação e processamento dos dados
        $produtosValidos = [];
        foreach ($dados as $linha) {
            if (!empty($linha['Código']) && !empty($linha['Nome'])) {
                $produtosValidos[] = [
                    'code' => $linha['Código'],
                    'name' => $linha['Nome'],
                    'description' => $linha['Descrição'] ?? '',
                    'unit' => $linha['Unidade'] ?? 'UN',
                    'cost_price' => $this->parseFloat($linha['Preço de Custo'] ?? 0),
                    'sale_price' => $this->parseFloat($linha['Preço de Venda'] ?? 0),
                    'stock_quantity' => $this->parseFloat($linha['Estoque'] ?? 0)
                ];
            }
        }

        return $produtosValidos;
    }

    /**
     * Faz download do arquivo
     */
    private function download(string $filename): void
    {
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $filename . '"');
        header('Cache-Control: max-age=0');

        $writer = new Xlsx($this->spreadsheet);
        $writer->save('php://output');
        exit;
    }

    /**
     * Salva o arquivo no servidor
     */
    private function salvar(string $filename): string
    {
        $dir = \ROOT_PATH . '/storage/exports';

        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        $filepath = $dir . '/' . $filename;

        $writer = new Xlsx($this->spreadsheet);
        $writer->save($filepath);

        return $filepath;
    }

    /**
     * Retorna o endereço da célula (ex: A1, B2)
     */
    private function getCellAddress(int $col, int $row): string
    {
        return $this->getColumnLetter($col) . $row;
    }

    /**
     * Retorna a letra da coluna
     */
    private function getColumnLetter(int $col): string
    {
        return \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
    }

    /**
     * Formata valor conforme tipo
     */
    private function formatarValor($valor, string $format)
    {
        switch ($format) {
            case 'date':
                return $valor ? date('d/m/Y', strtotime($valor)) : '';
            case 'datetime':
                return $valor ? date('d/m/Y H:i:s', strtotime($valor)) : '';
            case 'currency':
                return 'R$ ' . number_format((float) $valor, 2, ',', '.');
            case 'number':
                return number_format((float) $valor, 2, ',', '.');
            default:
                return $valor;
        }
    }

    /**
     * Converte string para float
     */
    private function parseFloat($value): float
    {
        if (is_numeric($value)) {
            return (float) $value;
        }

        // Remove formatação brasileira
        $value = str_replace(['R$', '.', ' '], '', $value);
        $value = str_replace(',', '.', $value);

        return (float) $value;
    }
}

