package de.cannamanage.service;

import de.cannamanage.service.model.report.MemberListReport;
import de.cannamanage.service.model.report.MonthlyReport;
import de.cannamanage.service.model.report.RecallReport;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * Generates CSV report exports using Apache Commons CSV.
 * All output is UTF-8 with BOM prefix for Excel compatibility.
 * German column headers for compliance documentation.
 */
@Component
public class CsvReportGenerator {

    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"));
    private static final String UTF8_BOM = "\uFEFF";

    /**
     * Render monthly report as CSV with daily breakdown.
     */
    public byte[] renderMonthlyReport(MonthlyReport report) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             OutputStreamWriter writer = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) {

            writer.write(UTF8_BOM);
            CSVPrinter csv = new CSVPrinter(writer,
                    CSVFormat.DEFAULT.builder()
                            .setHeader("Datum", "Menge (g)", "Ausgaben")
                            .build());

            if (report.getDailyBreakdown() != null) {
                for (MonthlyReport.DailyEntry entry : report.getDailyBreakdown()) {
                    csv.printRecord(
                            entry.getDate().format(DATE_FMT),
                            entry.getGrams().toPlainString(),
                            entry.getDistributions()
                    );
                }
            }

            csv.flush();
            return baos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("CSV generation failed", e);
        }
    }

    /**
     * Render member list as CSV.
     */
    public byte[] renderMemberList(MemberListReport report) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             OutputStreamWriter writer = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) {

            writer.write(UTF8_BOM);
            CSVPrinter csv = new CSVPrinter(writer,
                    CSVFormat.DEFAULT.builder()
                            .setHeader("Vorname", "Nachname", "Mitgliedsnr.", "Status",
                                    "Beitritt", "Ausgaben gesamt", "Letzte Ausgabe")
                            .build());

            for (MemberListReport.MemberEntry m : report.getMembers()) {
                csv.printRecord(
                        m.getFirstName(),
                        m.getLastName(),
                        m.getMembershipNumber(),
                        m.getStatus() != null ? m.getStatus().name() : "",
                        m.getJoinDate() != null ? m.getJoinDate().format(DATE_FMT) : "",
                        m.getTotalDistributions(),
                        m.getLastDistributionDate() != null ? DATETIME_FMT.format(m.getLastDistributionDate()) : ""
                );
            }

            csv.flush();
            return baos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("CSV generation failed", e);
        }
    }

    /**
     * Render recall report as CSV.
     */
    public byte[] renderRecallReport(RecallReport report) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             OutputStreamWriter writer = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) {

            writer.write(UTF8_BOM);
            CSVPrinter csv = new CSVPrinter(writer,
                    CSVFormat.DEFAULT.builder()
                            .setHeader("Vorname", "Nachname", "Ausgabedatum", "Menge (g)")
                            .build());

            for (RecallReport.AffectedMember am : report.getAffectedMembers()) {
                csv.printRecord(
                        am.getFirstName() != null ? am.getFirstName() : "",
                        am.getLastName() != null ? am.getLastName() : "",
                        am.getDistributionDate() != null ? DATETIME_FMT.format(am.getDistributionDate()) : "",
                        am.getGrams().toPlainString()
                );
            }

            csv.flush();
            return baos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("CSV generation failed", e);
        }
    }
}
