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 de.cannamanage.service.model.report.MemberListReport;
import de.cannamanage.service.model.report.MonthlyReport;
import de.cannamanage.service.model.report.RecallReport;
import org.springframework.stereotype.Component;

import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * Generates PDF reports using OpenPDF (librepdf fork of iText 2.x).
 * Minimal branding: club name header, report title, tables with light gray headers.
 */
@Component
public class PdfReportGenerator {

    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 NORMAL_FONT = new Font(Font.HELVETICA, 10, Font.NORMAL);
    private static final Font TABLE_HEADER_FONT = new Font(Font.HELVETICA, 9, Font.BOLD);
    private static final Font TABLE_CELL_FONT = new Font(Font.HELVETICA, 9, Font.NORMAL);
    private static final Color HEADER_BG = new Color(220, 220, 220);
    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("dd.MM.yyyy");
    private static final DateTimeFormatter DATETIME_FMT = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
            .withZone(ZoneId.of("Europe/Berlin"));

    /**
     * Render a monthly distribution report as PDF.
     */
    public byte[] renderMonthlyReport(MonthlyReport report, 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();

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

            // Report title
            Paragraph title = new Paragraph("Monatsbericht — " + report.getMonth().toString(), TITLE_FONT);
            title.setSpacingAfter(15);
            document.add(title);

            // Summary table
            PdfPTable summary = new PdfPTable(2);
            summary.setWidthPercentage(60);
            summary.setHorizontalAlignment(Element.ALIGN_LEFT);
            summary.setSpacingAfter(15);
            addSummaryRow(summary, "Ausgaben gesamt", String.valueOf(report.getTotalDistributions()));
            addSummaryRow(summary, "Gesamtmenge (g)", report.getTotalGrams().toPlainString());
            addSummaryRow(summary, "Eindeutige Mitglieder", String.valueOf(report.getUniqueMembers()));
            addSummaryRow(summary, "Ø pro Mitglied (g)", report.getAveragePerMember().toPlainString());
            document.add(summary);

            // Top strains
            if (report.getTopStrains() != null && !report.getTopStrains().isEmpty()) {
                document.add(new Paragraph("Top Sorten", TITLE_FONT));
                document.add(Chunk.NEWLINE);

                PdfPTable strainTable = new PdfPTable(3);
                strainTable.setWidthPercentage(80);
                strainTable.setSpacingAfter(15);
                addTableHeader(strainTable, "Sorte", "Menge (g)", "Ausgaben");
                for (MonthlyReport.StrainSummary s : report.getTopStrains()) {
                    addCell(strainTable, s.getName());
                    addCell(strainTable, s.getTotalGrams().toPlainString());
                    addCell(strainTable, String.valueOf(s.getDistributionCount()));
                }
                document.add(strainTable);
            }

            // Daily breakdown
            if (report.getDailyBreakdown() != null && !report.getDailyBreakdown().isEmpty()) {
                document.add(new Paragraph("Tagesübersicht", TITLE_FONT));
                document.add(Chunk.NEWLINE);

                PdfPTable dailyTable = new PdfPTable(3);
                dailyTable.setWidthPercentage(80);
                dailyTable.setSpacingAfter(15);
                addTableHeader(dailyTable, "Datum", "Menge (g)", "Ausgaben");
                for (MonthlyReport.DailyEntry e : report.getDailyBreakdown()) {
                    addCell(dailyTable, e.getDate().format(DATE_FMT));
                    addCell(dailyTable, e.getGrams().toPlainString());
                    addCell(dailyTable, String.valueOf(e.getDistributions()));
                }
                document.add(dailyTable);
            }

            document.close();
        } catch (DocumentException e) {
            throw new RuntimeException("PDF generation failed", e);
        }

        return baos.toByteArray();
    }

    /**
     * Render a member list report as PDF.
     */
    public byte[] renderMemberList(MemberListReport report, Club club) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Document document = new Document(PageSize.A4.rotate(), 50, 50, 50, 50);

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

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

            Paragraph title = new Paragraph("Mitgliederliste", TITLE_FONT);
            title.setSpacingAfter(15);
            document.add(title);

            PdfPTable table = new PdfPTable(7);
            table.setWidthPercentage(100);
            table.setWidths(new float[]{2f, 2f, 2f, 2f, 1.5f, 1.5f, 2.5f});
            addTableHeader(table, "Vorname", "Nachname", "Mitgliedsnr.", "Status",
                    "Beitritt", "Ausgaben", "Letzte Ausgabe");

            for (MemberListReport.MemberEntry m : report.getMembers()) {
                addCell(table, m.getFirstName());
                addCell(table, m.getLastName());
                addCell(table, m.getMembershipNumber());
                addCell(table, m.getStatus() != null ? m.getStatus().name() : "—");
                addCell(table, m.getJoinDate() != null ? m.getJoinDate().format(DATE_FMT) : "—");
                addCell(table, String.valueOf(m.getTotalDistributions()));
                addCell(table, m.getLastDistributionDate() != null
                        ? DATETIME_FMT.format(m.getLastDistributionDate()) : "—");
            }
            document.add(table);

            document.close();
        } catch (DocumentException e) {
            throw new RuntimeException("PDF generation failed", e);
        }

        return baos.toByteArray();
    }

    /**
     * Render a recall/batch trace report as PDF.
     */
    public byte[] renderRecallReport(RecallReport report, 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();

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

            Paragraph title = new Paragraph("Rückruf-Bericht — Charge " + report.getBatchNumber(), TITLE_FONT);
            title.setSpacingAfter(15);
            document.add(title);

            // Batch info
            PdfPTable info = new PdfPTable(2);
            info.setWidthPercentage(60);
            info.setHorizontalAlignment(Element.ALIGN_LEFT);
            info.setSpacingAfter(15);
            addSummaryRow(info, "Sorte", report.getStrainName());
            addSummaryRow(info, "Chargen-Nr.", report.getBatchNumber());
            addSummaryRow(info, "Erntedatum",
                    report.getReceivedDate() != null ? report.getReceivedDate().format(DATE_FMT) : "—");
            addSummaryRow(info, "Verteilte Menge (g)", report.getTotalGramsDistributed().toPlainString());
            addSummaryRow(info, "Betroffene Mitglieder", String.valueOf(report.getAffectedMembers().size()));
            document.add(info);

            // Affected members table
            document.add(new Paragraph("Betroffene Mitglieder", TITLE_FONT));
            document.add(Chunk.NEWLINE);

            PdfPTable table = new PdfPTable(4);
            table.setWidthPercentage(100);
            addTableHeader(table, "Vorname", "Nachname", "Ausgabedatum", "Menge (g)");

            for (RecallReport.AffectedMember am : report.getAffectedMembers()) {
                addCell(table, am.getFirstName() != null ? am.getFirstName() : "—");
                addCell(table, am.getLastName() != null ? am.getLastName() : "—");
                addCell(table, am.getDistributionDate() != null
                        ? DATETIME_FMT.format(am.getDistributionDate()) : "—");
                addCell(table, am.getGrams().toPlainString());
            }
            document.add(table);

            document.close();
        } catch (DocumentException e) {
            throw new RuntimeException("PDF generation failed", e);
        }

        return baos.toByteArray();
    }

    // --- Helper methods ---

    private void addTableHeader(PdfPTable table, String... headers) {
        for (String h : headers) {
            PdfPCell cell = new PdfPCell(new Phrase(h, TABLE_HEADER_FONT));
            cell.setBackgroundColor(HEADER_BG);
            cell.setPadding(5);
            table.addCell(cell);
        }
    }

    private void addCell(PdfPTable table, String text) {
        PdfPCell cell = new PdfPCell(new Phrase(text, TABLE_CELL_FONT));
        cell.setPadding(4);
        table.addCell(cell);
    }

    private void addSummaryRow(PdfPTable table, String label, String value) {
        PdfPCell labelCell = new PdfPCell(new Phrase(label, TABLE_HEADER_FONT));
        labelCell.setBorder(Rectangle.NO_BORDER);
        labelCell.setPadding(4);
        table.addCell(labelCell);

        PdfPCell valueCell = new PdfPCell(new Phrase(value, TABLE_CELL_FONT));
        valueCell.setBorder(Rectangle.NO_BORDER);
        valueCell.setPadding(4);
        table.addCell(valueCell);
    }
}
