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.domain.entity.Member;
import de.cannamanage.domain.entity.Payment;
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.format.DateTimeFormatter;
import java.util.Locale;

/**
 * Generates receipt (Quittung) PDFs for member payments.
 * Layout: A4 portrait, single page, professional receipt format.
 * Legal basis: §147 AO (10-year retention for Buchungsbelege).
 */
@Service
public class ReceiptPdfService {

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

    private static final Font CLUB_NAME_FONT = new Font(Font.HELVETICA, 14, Font.BOLD);
    private static final Font CLUB_ADDRESS_FONT = new Font(Font.HELVETICA, 9, Font.NORMAL, Color.DARK_GRAY);
    private static final Font TITLE_FONT = new Font(Font.HELVETICA, 18, Font.BOLD);
    private static final Font RECEIPT_NR_FONT = new Font(Font.HELVETICA, 10, Font.NORMAL, Color.GRAY);
    private static final Font LABEL_FONT = new Font(Font.HELVETICA, 10, Font.BOLD);
    private static final Font VALUE_FONT = new Font(Font.HELVETICA, 10, Font.NORMAL);
    private static final Font AMOUNT_FONT = new Font(Font.HELVETICA, 14, Font.BOLD);
    private static final Font FOOTER_FONT = new Font(Font.HELVETICA, 8, Font.ITALIC, Color.GRAY);
    private static final Font SIGNATURE_FONT = new Font(Font.HELVETICA, 9, Font.NORMAL);

    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("dd.MM.yyyy");
    private static final DateTimeFormatter PERIOD_FMT = DateTimeFormatter.ofPattern("MMMM yyyy", Locale.GERMAN);

    /**
     * Generate a receipt PDF for a payment.
     *
     * @param payment the payment record
     * @param member  the paying member
     * @param club    the club entity (for header)
     * @return PDF bytes
     */
    public byte[] generateReceipt(Payment payment, Member member, Club club) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // A4 with generous margins
        Document document = new Document(PageSize.A4, 60, 60, 60, 60);

        try {
            PdfWriter.getInstance(document, baos);
            document.open();

            // --- Club Header ---
            Paragraph clubName = new Paragraph(club.getName(), CLUB_NAME_FONT);
            clubName.setAlignment(Element.ALIGN_LEFT);
            document.add(clubName);

            if (club.getAddress() != null && !club.getAddress().isBlank()) {
                Paragraph address = new Paragraph(club.getAddress(), CLUB_ADDRESS_FONT);
                address.setSpacingAfter(5);
                document.add(address);
            }

            // Horizontal rule
            Paragraph hr = new Paragraph(" ");
            hr.setSpacingBefore(5);
            hr.setSpacingAfter(15);
            document.add(hr);

            // --- Title ---
            Paragraph title = new Paragraph("QUITTUNG", TITLE_FONT);
            title.setAlignment(Element.ALIGN_CENTER);
            title.setSpacingAfter(5);
            document.add(title);

            // Receipt number
            String receiptNr = payment.getReceiptNumber() != null
                    ? payment.getReceiptNumber()
                    : "CM-" + payment.getId().toString().substring(0, 8).toUpperCase();
            Paragraph nrPara = new Paragraph("Nr. " + receiptNr, RECEIPT_NR_FONT);
            nrPara.setAlignment(Element.ALIGN_CENTER);
            nrPara.setSpacingAfter(30);
            document.add(nrPara);

            // --- Receipt Details Table ---
            PdfPTable detailsTable = new PdfPTable(2);
            detailsTable.setWidthPercentage(80);
            detailsTable.setHorizontalAlignment(Element.ALIGN_LEFT);
            detailsTable.setWidths(new float[]{35f, 65f});
            detailsTable.setSpacingAfter(20);

            addDetailRow(detailsTable, "Erhalten von:", getMemberDisplayName(member));
            addDetailRow(detailsTable, "Mitgliedsnr.:", member.getMemberNumber() != null
                    ? member.getMemberNumber() : "—");

            // Amount - formatted as Euro
            BigDecimal amount = BigDecimal.valueOf(payment.getAmountCents()).divide(BigDecimal.valueOf(100));
            String amountStr = String.format(Locale.GERMAN, "%,.2f €", amount);
            addDetailRow(detailsTable, "Betrag:", amountStr, AMOUNT_FONT);

            addDetailRow(detailsTable, "Datum:", payment.getPaymentDate().format(DATE_FMT));
            addDetailRow(detailsTable, "Zahlungsart:", translatePaymentMethod(payment.getPaymentMethod().name()));

            // Period covered
            if (payment.getPeriodFrom() != null && payment.getPeriodTo() != null) {
                String period = formatPeriod(payment.getPeriodFrom(), payment.getPeriodTo());
                addDetailRow(detailsTable, "Zeitraum:", period);
            }

            addDetailRow(detailsTable, "Verwendung:", "Mitgliedsbeitrag");

            if (payment.getReference() != null && !payment.getReference().isBlank()) {
                addDetailRow(detailsTable, "Referenz:", payment.getReference());
            }

            document.add(detailsTable);

            // --- Spacer ---
            document.add(new Paragraph(" "));
            document.add(new Paragraph(" "));
            document.add(new Paragraph(" "));

            // --- Signature Section ---
            PdfPTable sigTable = new PdfPTable(2);
            sigTable.setWidthPercentage(80);
            sigTable.setHorizontalAlignment(Element.ALIGN_LEFT);
            sigTable.setWidths(new float[]{50f, 50f});

            // Date line
            PdfPCell dateCell = new PdfPCell();
            dateCell.setBorder(Rectangle.TOP);
            dateCell.setBorderWidth(0.5f);
            dateCell.setPaddingTop(5);
            dateCell.addElement(new Phrase("Datum", SIGNATURE_FONT));
            sigTable.addCell(dateCell);

            // Signature line
            PdfPCell sigCell = new PdfPCell();
            sigCell.setBorder(Rectangle.TOP);
            sigCell.setBorderWidth(0.5f);
            sigCell.setPaddingTop(5);
            sigCell.addElement(new Phrase("Unterschrift Kassenwart", SIGNATURE_FONT));
            sigTable.addCell(sigCell);

            document.add(sigTable);

            // --- Footer ---
            Paragraph footer = new Paragraph(
                    "Anbauvereinigung gemäß §2 KCanG — " + club.getName(),
                    FOOTER_FONT
            );
            footer.setAlignment(Element.ALIGN_CENTER);
            footer.setSpacingBefore(40);
            document.add(footer);

            document.close();

        } catch (DocumentException e) {
            log.error("Failed to generate receipt PDF for payment {}", payment.getId(), e);
            throw new RuntimeException("PDF generation failed", e);
        }

        return baos.toByteArray();
    }

    private void addDetailRow(PdfPTable table, String label, String value) {
        addDetailRow(table, label, value, VALUE_FONT);
    }

    private void addDetailRow(PdfPTable table, String label, String value, Font valueFont) {
        PdfPCell labelCell = new PdfPCell(new Phrase(label, LABEL_FONT));
        labelCell.setBorder(Rectangle.NO_BORDER);
        labelCell.setPaddingBottom(8);
        table.addCell(labelCell);

        PdfPCell valueCell = new PdfPCell(new Phrase(value, valueFont));
        valueCell.setBorder(Rectangle.NO_BORDER);
        valueCell.setPaddingBottom(8);
        table.addCell(valueCell);
    }

    private String getMemberDisplayName(Member member) {
        String firstName = member.getFirstName() != null ? member.getFirstName() : "";
        String lastName = member.getLastName() != null ? member.getLastName() : "";
        return (firstName + " " + lastName).trim();
    }

    private String translatePaymentMethod(String method) {
        return switch (method) {
            case "CASH" -> "Bar";
            case "BANK_TRANSFER" -> "Überweisung";
            case "SEPA" -> "SEPA-Lastschrift";
            case "CARD" -> "Kartenzahlung";
            default -> method;
        };
    }

    private String formatPeriod(LocalDate from, LocalDate to) {
        if (from.getMonth() == to.getMonth() && from.getYear() == to.getYear()) {
            return from.format(PERIOD_FMT);
        }
        return from.format(PERIOD_FMT) + " – " + to.format(PERIOD_FMT);
    }
}
