package br.gov.sigefp.common.service;

import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.FontFactory;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Override
    public byte[] generateExcel(List<?> data, Map<String, String> headers, String sheetName) {
        try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            Sheet sheet = workbook.createSheet(sheetName);

            // Create Header Row
            Row headerRow = sheet.createRow(0);
            CellStyle headerStyle = workbook.createCellStyle();
            org.apache.poi.ss.usermodel.Font font = workbook.createFont();
            font.setBold(true);
            headerStyle.setFont(font);

            int col = 0;
            for (String title : headers.values()) {
                Cell cell = headerRow.createCell(col++);
                cell.setCellValue(title);
                cell.setCellStyle(headerStyle);
            }

            // Populate Data
            int rowIdx = 1;
            for (Object item : data) {
                Row row = sheet.createRow(rowIdx++);
                col = 0;
                for (String fieldName : headers.keySet()) {
                    Cell cell = row.createCell(col++);
                    Object value = getFieldValue(item, fieldName);
                    if (value != null) {
                        cell.setCellValue(formatValue(value));
                    }
                }
            }

            workbook.write(out);
            return out.toByteArray();

        } catch (Exception e) {
            log.error("Erro ao gerar relatório Excel", e);
            throw new RuntimeException("Falha na geração do Excel", e);
        }
    }

    @Override
    public byte[] generatePdf(List<?> data, Map<String, String> headers, String title) {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            Document document = new Document(PageSize.A4.rotate());
            PdfWriter.getInstance(document, out);

            document.open();

            // --- Cabelho Institucional ---

            // Fonte para o cabeçalho
            com.lowagie.text.Font headerFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 12);
            com.lowagie.text.Font subHeaderFont = FontFactory.getFont(FontFactory.HELVETICA, 10);

            Paragraph textHeader = new Paragraph();
            textHeader.setAlignment(Element.ALIGN_CENTER);
            textHeader.add(new Phrase("REPÚBLICA DA GUINÉ-BISSAU\n", headerFont));
            textHeader.add(new Phrase("MINISTÉRIO DA ECONOMIA E FINANÇAS\n", headerFont));
            textHeader.add(new Phrase("DIREÇÃO GERAL DO ORÇAMENTO\n", subHeaderFont));
            textHeader.add(new Phrase("SIGEFP - SISTEMA INTEGRADO DE GESTÃO FINANCEIRA\n", subHeaderFont));
            textHeader.setSpacingAfter(20);
            document.add(textHeader);

            // Linha separadora
            com.lowagie.text.pdf.draw.LineSeparator ls = new com.lowagie.text.pdf.draw.LineSeparator();
            document.add(new Paragraph(new com.lowagie.text.Chunk(ls)));
            document.add(new Paragraph(" ")); // Espaço

            // --- Título do Relatório ---
            com.lowagie.text.Font titleFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 14);
            Paragraph titlePara = new Paragraph(title.toUpperCase(), titleFont);
            titlePara.setAlignment(Element.ALIGN_CENTER);
            titlePara.setSpacingAfter(15);
            document.add(titlePara);

            // Data de Emissão
            Paragraph datePara = new Paragraph(
                    "Emitido em: "
                            + java.time.LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")),
                    FontFactory.getFont(FontFactory.HELVETICA, 8));
            datePara.setAlignment(Element.ALIGN_RIGHT);
            datePara.setSpacingAfter(10);
            document.add(datePara);

            // --- Tabela de Dados ---
            PdfPTable table = new PdfPTable(headers.size());
            table.setWidthPercentage(100);
            table.setSpacingBefore(10f);
            table.setSpacingAfter(10f);

            // Estilo do Cabeçalho da Tabela
            com.lowagie.text.Font tableHeaderFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 10,
                    java.awt.Color.WHITE);

            for (String headerTitle : headers.values()) {
                PdfPCell cell = new PdfPCell(new Phrase(headerTitle, tableHeaderFont));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
                cell.setBackgroundColor(java.awt.Color.DARK_GRAY);
                cell.setPadding(5);
                table.addCell(cell);
            }

            // Estilo dos Dados
            com.lowagie.text.Font dataFont = FontFactory.getFont(FontFactory.HELVETICA, 9);
            boolean alternate = false;
            java.awt.Color lightGray = new java.awt.Color(240, 240, 240);

            for (Object item : data) {
                for (String fieldName : headers.keySet()) {
                    Object value = getFieldValue(item, fieldName);
                    PdfPCell cell = new PdfPCell(new Phrase(value != null ? formatValue(value) : "", dataFont));
                    cell.setPadding(4);
                    cell.setVerticalAlignment(Element.ALIGN_MIDDLE);

                    if (alternate) {
                        cell.setBackgroundColor(lightGray);
                    }
                    table.addCell(cell);
                }
                alternate = !alternate;
            }

            document.add(table);

            // --- Rodapé Simples ---
            Paragraph footer = new Paragraph(
                    "Documento processado eletronicamente pelo SIGEFP. A autenticidade pode ser verificada no sistema.",
                    FontFactory.getFont(FontFactory.HELVETICA_OBLIQUE, 8));
            footer.setAlignment(Element.ALIGN_CENTER);
            footer.setSpacingBefore(20);
            document.add(footer);

            document.close();

            return out.toByteArray();

        } catch (Exception e) {
            log.error("Erro ao gerar relatório PDF", e);
            throw new RuntimeException("Falha na geração do PDF", e);
        }
    }

    // Helper to get field value via reflection
    private Object getFieldValue(Object object, String fieldName) {
        if (object == null || fieldName == null) {
            return null;
        }

        // Suporte para Map (colunas dinâmicas)
        if (object instanceof Map) {
            return ((Map<?, ?>) object).get(fieldName);
        }

        // Primeiro, tentar via getter (mais seguro com Lombok @Data)
        try {
            String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
            java.lang.reflect.Method getter = object.getClass().getMethod(getterName);
            return getter.invoke(object);
        } catch (NoSuchMethodException e) {
            // Tentar campo direto
        } catch (Exception e) {
            log.debug("Erro ao invocar getter para {}: {}", fieldName, e.getMessage());
        }

        // Fallback: tentar campo direto
        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(object);
        } catch (NoSuchFieldException e) {
            log.debug("Campo não encontrado: {}", fieldName);
            return null;
        } catch (IllegalAccessException e) {
            log.debug("Erro ao acessar campo {}: {}", fieldName, e.getMessage());
            return null;
        }
    }

    private String formatValue(Object value) {
        if (value == null)
            return "";

        if (value instanceof java.time.LocalDate) {
            return ((java.time.LocalDate) value).format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
        } else if (value instanceof java.time.LocalDateTime) {
            return ((java.time.LocalDateTime) value).format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
        } else if (value instanceof java.math.BigDecimal) {
            // Formatar moeda (XOF/BCEAO geralmente usa espaço como separador de milhar e
            // vírgula ou ponto, vamos usar padrão PT-BR para consistência com o frontend)
            java.text.NumberFormat nf = java.text.NumberFormat.getInstance(new java.util.Locale("pt", "BR"));
            nf.setMinimumFractionDigits(2);
            return nf.format(value);
        } else if (value instanceof String) {
            // Traduções rápidas para valores conhecidos
            String s = (String) value;
            return switch (s) {
                case "COMMITMENT" -> "Empenho";
                case "LIQUIDATION" -> "Liquidação";
                case "PAYMENT" -> "Pagamento";
                case "INITIAL_ALLOCATION" -> "Dotação Inicial";
                case "SUPPLEMENTARY_CREDIT" -> "Crédito Suplementar";
                default -> s;
            };
        }
        return value.toString();
    }
}
