import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { connectDB } from "@/lib/db";
import { Order } from "@/models/Order";
import { Invoice } from "@/models/Invoice";
import { Expense } from "@/models/Expense";
import { Income } from "@/models/Income";
import { EXPENSE_CATEGORY_LABELS, type ExpenseCategory } from "@/lib/expenseConstants";
import { getSessionClientId } from "@/lib/auth";
import { isAdminSession, hasPermission } from "@/lib/adminAuth";
import { corsHeaders, corsPreflight } from "@/lib/teamApiCors";
import { formatDateDE, formatDateTimeDE } from "@/lib/orderConstants";

export async function OPTIONS(request: NextRequest) {
  return corsPreflight(request);
}

// Cross-Origin-Pendant zu /api/admin/euer-export — identische CSV-Logik,
// nur mit CORS-Headern für den authentifizierten fetch() aus der App.
function csvEscape(value: string | number): string {
  const s = String(value);
  return /[",\n;]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
}

export async function GET(request: NextRequest) {
  const headers = corsHeaders(request);
  const clientId = await getSessionClientId();
  if (!clientId || !(await isAdminSession()) || !(await hasPermission("statistics"))) {
    return NextResponse.json({ error: "Nicht angemeldet." }, { status: 401, headers });
  }

  const yearParam = request.nextUrl.searchParams.get("year");
  const year = yearParam ? parseInt(yearParam, 10) : new Date().getFullYear();
  if (!Number.isFinite(year)) return NextResponse.json({ error: "Ungültiges Jahr." }, { status: 400, headers });

  const rangeStart = new Date(Date.UTC(year, 0, 1));
  const rangeEnd = new Date(Date.UTC(year + 1, 0, 1));

  await connectDB();
  const [paidOrders, expenses, manualIncome, refundedOrders] = await Promise.all([
    Order.find({ paid: true, paidAt: { $gte: rangeStart, $lt: rangeEnd } }).lean(),
    Expense.find({ date: { $gte: rangeStart, $lt: rangeEnd } }).sort({ date: 1 }).lean(),
    Income.find({ date: { $gte: rangeStart, $lt: rangeEnd } }).sort({ date: 1 }).lean(),
    Order.find({ refundedAmount: { $gt: 0 }, refundedAt: { $gte: rangeStart, $lt: rangeEnd } })
      .select("characterOrConcept refundedAmount refundedAt refundNote")
      .lean(),
  ]);
  const invoicesByOrderId = new Map(
    (await Invoice.find({ orderId: { $in: paidOrders.map((o) => o._id) } }).lean()).map((inv) => [String(inv.orderId), inv])
  );

  const ordersMissingInvoice: string[] = [];
  const orderIncomeRows = paidOrders.map((o) => {
    const invoice = invoicesByOrderId.get(String(o._id));
    if (!invoice) ordersMissingInvoice.push(o.characterOrConcept);
    return {
      date: o.paidAt as Date,
      description: invoice ? `${o.characterOrConcept} (Rechnung ${invoice.number})` : `⚠ ${o.characterOrConcept} — KEINE RECHNUNG, BETRAG PRÜFEN`,
      amount: invoice?.totalAmount ?? 0,
    };
  });
  const manualIncomeRows = manualIncome.map((i) => ({ date: i.date, description: `${i.description} (manuell erfasst)`, amount: i.amount }));
  const refundRows = refundedOrders.map((o) => ({
    date: o.refundedAt as Date,
    description: `⤷ Rückerstattung: ${o.characterOrConcept}${o.refundNote ? ` (${o.refundNote})` : ""}`,
    amount: -o.refundedAmount,
  }));
  const incomeRows = [...orderIncomeRows, ...manualIncomeRows, ...refundRows].sort((a, b) => a.date.getTime() - b.date.getTime());

  const totalIncome = incomeRows.reduce((sum, r) => sum + r.amount, 0);
  const totalExpenses = expenses.reduce((sum, e) => sum + e.amount, 0);

  const lines: string[] = [];
  lines.push(`EÜR-Vorbereitung ${year} — Rakku Photography`);
  lines.push(`Erzeugt am;${formatDateTimeDE(new Date())}`);
  lines.push("");
  lines.push(`Betriebseinnahmen gesamt;${totalIncome.toFixed(2)} EUR`);
  lines.push(`Betriebsausgaben gesamt;${totalExpenses.toFixed(2)} EUR`);
  lines.push(`Gewinn / Verlust;${(totalIncome - totalExpenses).toFixed(2)} EUR`);
  if (ordersMissingInvoice.length > 0) {
    lines.push("");
    lines.push(
      `⚠ ACHTUNG;${ordersMissingInvoice.length} als bezahlt markierte(r) Auftrag/Aufträge ohne Rechnung — Betrag fehlt oben in „Betriebseinnahmen gesamt". Rechnung nachtragen und Export neu ziehen: ${ordersMissingInvoice.join(", ")}`
    );
  }
  lines.push("");

  lines.push("BETRIEBSEINNAHMEN");
  lines.push(["Datum", "Beschreibung", "Betrag (EUR)"].map(csvEscape).join(";"));
  for (const r of incomeRows) {
    lines.push([formatDateDE(new Date(r.date)), r.description, r.amount.toFixed(2)].map(csvEscape).join(";"));
  }
  lines.push("");

  lines.push("BETRIEBSAUSGABEN");
  lines.push(["Datum", "Kategorie", "Beschreibung", "Betrag (EUR)", "davon USt. (EUR)"].map(csvEscape).join(";"));
  for (const e of expenses) {
    lines.push([formatDateDE(new Date(e.date)), EXPENSE_CATEGORY_LABELS[e.category as ExpenseCategory], e.description, e.amount.toFixed(2), (e.vatAmount || 0).toFixed(2)].map(csvEscape).join(";"));
  }

  const csv = "﻿" + lines.join("\n");
  return new NextResponse(csv, { headers: { ...headers, "Content-Type": "text/csv; charset=utf-8", "Cache-Control": "private, max-age=0, no-store" } });
}
