package de.cannamanage.service;

import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import de.cannamanage.domain.entity.Club;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Generates the annual financial report (Jahresabschluss) as PDF.
 * Content: Income/expense totals, monthly breakdown, category breakdown, member payment summary.
 * Legal basis: §259 BGB (Rechenschaftspflicht), §147 AO (10-year retention).
 */
@Service
public class FinancialReportService {

    private static final Logger log = LoggerFactory.getLogger(FinancialReportService.class);

    private static final Font HEADER_FONT = new Font(Font.HELVETICA, 16, Font.BOLD);
    private static final Font TITLE_FONT = new Font(Font.HELVETICA, 12, Font.BOLD);
    private static final Font SUBTITLE_FONT = new Font(Font.HELVETICA, 10, Font.BOLD);
    private static final Font NORMAL_FONT = new Font(Font.HELVETICA, 10, Font.NORMAL);
    private static final Font TABLE_HEADER_FONT = new Font(Font.HELVETICA, 9, Font.BOLD, Color.WHITE);
    private static final Font TABLE_CELL_FONT = new Font(Font.HELVETICA, 9, Font.NORMAL);
    private static final Font TABLE_CELL_BOLD = new Font(Font.HELVETICA, 9, Font.BOLD);
    private static final Font FOOTER_FONT = new Font(Font.HELVETICA, 8, Font.ITALIC, Color.GRAY);

    private static final Color PRIMARY_COLOR = new Color(34, 87, 58); // Dark green
    private static final Color HEADER_BG = new Color(34, 87, 58);
    private static final Color LIGHT_BG = new Color(245, 248, 245);
    private static final Color INCOME_COLOR = new Color(22, 163, 74);
    private static final Color EXPENSE_COLOR = new Color(220, 38, 38);

    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("dd.MM.yyyy");

    /**
     * DTO for annual report data.
     */
    public record AnnualReportData(
            int year,
            BigDecimal totalIncome,
            BigDecimal totalExpenses,
            BigDecimal netBalance,
            List<MonthlyBreakdown> monthlyBreakdown,
            List<CategoryBreakdown> expensesByCategory,
            int totalMembers,
            int paidMembers,
            BigDecimal totalOutstanding
    ) {}

    public record MonthlyBreakdown(
            int month,
            String monthName,
            BigDecimal income,
            BigDecimal expenses,
            BigDecimal net
    ) {}

    public record CategoryBreakdown(
            String category,
            BigDecimal amount,
            double percentage
    ) {}

    /**
     * Generate the annual financial report PDF.
     */
    public byte[] generateAnnualReport(AnnualReportData data, Club club) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Document document = new Document(PageSize.A4, 50, 50, 50, 50);

        try {
            PdfWriter writer = PdfWriter.getInstance(document, baos);
            writer.setPageEvent(new PdfFooterHandler());
            document.open();

            // === Page 1: Cover & Summary ===

            // Club header
            Paragraph clubHeader = new Paragraph(club.getName(), HEADER_FONT);
            clubHeader.setSpacingAfter(5);
            document.add(clubHeader);

            // Title
            Paragraph title = new Paragraph(
                    "Jahresabschluss " + data.year(), TITLE_FONT);
            title.setSpacingAfter(5);
            document.add(title);

            // Subtitle
            Paragraph subtitle = new Paragraph(
                    "Finanzübersicht für das Geschäftsjahr " + data.year(),
                    NORMAL_FONT);
            subtitle.setSpacingAfter(20);
            document.add(subtitle);

            // --- Summary KPIs ---
            addSectionTitle(document, "Zusammenfassung");

            PdfPTable summaryTable = new PdfPTable(2);
            summaryTable.setWidthPercentage(60);
            summaryTable.setHorizontalAlignment(Element.ALIGN_LEFT);
            summaryTable.setSpacingAfter(20);

            addSummaryRow(summaryTable, "Gesamteinnahmen",
                    formatEuro(data.totalIncome()), INCOME_COLOR);
            addSummaryRow(summaryTable, "Gesamtausgaben",
                    formatEuro(data.totalExpenses()), EXPENSE_COLOR);
            addSummaryRow(summaryTable, "Saldo",
                    formatEuro(data.netBalance()),
                    data.netBalance().signum() >= 0 ? INCOME_COLOR : EXPENSE_COLOR);

            document.add(summaryTable);

            // --- Member payment summary ---
            addSectionTitle(document, "Mitgliederbeiträge");

            PdfPTable memberTable = new PdfPTable(2);
            memberTable.setWidthPercentage(60);
            memberTable.setHorizontalAlignment(Element.ALIGN_LEFT);
            memberTable.setSpacingAfter(20);

            addSummaryRow(memberTable, "Mitglieder gesamt",
                    String.valueOf(data.totalMembers()), Color.BLACK);
            addSummaryRow(memberTable, "Beiträge bezahlt",
                    String.valueOf(data.paidMembers()), INCOME_COLOR);
            addSummaryRow(memberTable, "Offene Beiträge",
                    formatEuro(data.totalOutstanding()), EXPENSE_COLOR);

            document.add(memberTable);

            // --- Monthly Breakdown Table ---
            addSectionTitle(document, "Monatliche Übersicht");

            PdfPTable monthlyTable = new PdfPTable(4);
            monthlyTable.setWidthPercentage(100);
            monthlyTable.setWidths(new float[]{30f, 23f, 23f, 24f});
            monthlyTable.setSpacingAfter(20);

            addColoredHeader(monthlyTable, "Monat");
            addColoredHeader(monthlyTable, "Einnahmen");
            addColoredHeader(monthlyTable, "Ausgaben");
            addColoredHeader(monthlyTable, "Saldo");

            BigDecimal runningTotal = BigDecimal.ZERO;
            for (MonthlyBreakdown month : data.monthlyBreakdown()) {
                runningTotal = runningTotal.add(month.net());

                boolean isEven = month.month() % 2 == 0;
                Color rowBg = isEven ? LIGHT_BG : Color.WHITE;

                addCellWithBg(monthlyTable, month.monthName(), TABLE_CELL_FONT, rowBg);
                addCellWithBg(monthlyTable, formatEuro(month.income()), TABLE_CELL_FONT, rowBg);
                addCellWithBg(monthlyTable, formatEuro(month.expenses()), TABLE_CELL_FONT, rowBg);
                addCellWithBg(monthlyTable, formatEuro(month.net()), TABLE_CELL_FONT, rowBg);
            }

            // Total row
            addCellWithBg(monthlyTable, "GESAMT", TABLE_CELL_BOLD, LIGHT_BG);
            addCellWithBg(monthlyTable, formatEuro(data.totalIncome()), TABLE_CELL_BOLD, LIGHT_BG);
            addCellWithBg(monthlyTable, formatEuro(data.totalExpenses()), TABLE_CELL_BOLD, LIGHT_BG);
            addCellWithBg(monthlyTable, formatEuro(data.netBalance()), TABLE_CELL_BOLD, LIGHT_BG);

            document.add(monthlyTable);

            // --- Expense Breakdown by Category ---
            if (data.expensesByCategory() != null && !data.expensesByCategory().isEmpty()) {
                addSectionTitle(document, "Ausgaben nach Kategorie");

                PdfPTable categoryTable = new PdfPTable(3);
                categoryTable.setWidthPercentage(80);
                categoryTable.setWidths(new float[]{45f, 30f, 25f});
                categoryTable.setSpacingAfter(20);

                addColoredHeader(categoryTable, "Kategorie");
                addColoredHeader(categoryTable, "Betrag");
                addColoredHeader(categoryTable, "Anteil");

                for (CategoryBreakdown cat : data.expensesByCategory()) {
                    addCell(categoryTable, translateCategory(cat.category()));
                    addCell(categoryTable, formatEuro(cat.amount()));
                    addCell(categoryTable, String.format("%.1f%%", cat.percentage()));
                }

                document.add(categoryTable);
            }

            // --- Footer note ---
            Paragraph footerNote = new Paragraph(
                    "Erstellt am " + LocalDate.now().format(DATE_FMT)
                            + " — Anbauvereinigung gemäß §2 KCanG",
                    FOOTER_FONT);
            footerNote.setAlignment(Element.ALIGN_CENTER);
            footerNote.setSpacingBefore(30);
            document.add(footerNote);

            document.close();

        } catch (DocumentException e) {
            log.error("Failed to generate annual report PDF for year {}", data.year(), e);
            throw new RuntimeException("PDF generation failed", e);
        }

        return baos.toByteArray();
    }

    // --- Helper methods ---

    private void addSectionTitle(Document document, String text) throws DocumentException {
        Paragraph section = new Paragraph(text, SUBTITLE_FONT);
        section.setSpacingBefore(10);
        section.setSpacingAfter(8);
        document.add(section);
    }

    private void addSummaryRow(PdfPTable table, String label, String value, Color valueColor) {
        PdfPCell labelCell = new PdfPCell(new Phrase(label, NORMAL_FONT));
        labelCell.setBorder(Rectangle.NO_BORDER);
        labelCell.setPaddingBottom(5);
        table.addCell(labelCell);

        Font valueFont = new Font(Font.HELVETICA, 10, Font.BOLD, valueColor);
        PdfPCell valueCell = new PdfPCell(new Phrase(value, valueFont));
        valueCell.setBorder(Rectangle.NO_BORDER);
        valueCell.setPaddingBottom(5);
        valueCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(valueCell);
    }

    private void addColoredHeader(PdfPTable table, String text) {
        PdfPCell cell = new PdfPCell(new Phrase(text, TABLE_HEADER_FONT));
        cell.setBackgroundColor(HEADER_BG);
        cell.setPadding(6);
        cell.setBorderWidth(0);
        table.addCell(cell);
    }

    private void addCell(PdfPTable table, String text) {
        PdfPCell cell = new PdfPCell(new Phrase(text, TABLE_CELL_FONT));
        cell.setPadding(5);
        cell.setBorderWidth(0.5f);
        cell.setBorderColor(Color.LIGHT_GRAY);
        table.addCell(cell);
    }

    private void addCellWithBg(PdfPTable table, String text, Font font, Color bg) {
        PdfPCell cell = new PdfPCell(new Phrase(text, font));
        cell.setBackgroundColor(bg);
        cell.setPadding(5);
        cell.setBorderWidth(0.5f);
        cell.setBorderColor(Color.LIGHT_GRAY);
        table.addCell(cell);
    }

    private String formatEuro(BigDecimal amount) {
        return String.format(Locale.GERMAN, "%,.2f €", amount);
    }

    private String translateCategory(String category) {
        return switch (category) {
            case "RENT" -> "Miete";
            case "UTILITIES" -> "Nebenkosten";
            case "EQUIPMENT" -> "Ausstattung";
            case "SEEDS" -> "Saatgut";
            case "SUPPLIES" -> "Verbrauchsmaterial";
            case "INSURANCE" -> "Versicherung";
            case "LEGAL" -> "Rechtsberatung";
            case "OTHER" -> "Sonstiges";
            default -> category;
        };
    }
}
