import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { errorResponse } from '@/lib/errors';
import {
  getFinancialKpis,
  getRevenueByMonth,
  getCollectionFunnel,
  getExpectedDepositAging,
  getCashFlow,
  getExpenseBreakdown,
  getOutstandingDeposits,
  getRecentPayments,
  getRefundLog,
  getExpenseLedger,
  financialHasData,
} from '@/lib/services/reports/financial.service';

/**
 * GET /api/v1/reports/financial?from=&to=
 *
 * Financial report payload, sourced from the canonical `payments` +
 * `expenses` tables (the CRM records money received; it does not invoice
 * — see docs/reports-content-spec.md § Report 02). "Outstanding AR" is
 * reframed as expected-deposit shortfall on active deals.
 *
 * Permission: `reports.view_dashboard` (same gate as the other report
 * dashboards).
 */
const querySchema = z.object({
  from: z.string().datetime().optional(),
  to: z.string().datetime().optional(),
});

function resolveRange(from?: string, to?: string): { from: Date; to: Date } {
  const now = new Date();
  // Default: trailing 12 months — financial trends read better over a
  // year than 30 days, and the month/cash-flow charts want the span.
  const defaultFrom = new Date(now);
  defaultFrom.setMonth(defaultFrom.getMonth() - 12);
  return {
    from: from ? new Date(from) : defaultFrom,
    to: to ? new Date(to) : now,
  };
}

export const GET = withAuth(
  withPermission('reports', 'view_dashboard', async (req: NextRequest, ctx) => {
    try {
      const params = req.nextUrl.searchParams;
      const { from, to } = querySchema.parse({
        from: params.get('from') ?? undefined,
        to: params.get('to') ?? undefined,
      });
      const range = resolveRange(from, to);

      const [
        kpis,
        revenueByMonth,
        collectionFunnel,
        aging,
        cashFlow,
        expenseBreakdown,
        outstandingDeposits,
        recentPayments,
        refundLog,
        expenseLedger,
        hasData,
      ] = await Promise.all([
        getFinancialKpis(ctx.portId, range),
        getRevenueByMonth(ctx.portId, range),
        getCollectionFunnel(ctx.portId, range),
        getExpectedDepositAging(ctx.portId),
        getCashFlow(ctx.portId, range),
        getExpenseBreakdown(ctx.portId, range),
        getOutstandingDeposits(ctx.portId),
        getRecentPayments(ctx.portId, range),
        getRefundLog(ctx.portId, range),
        getExpenseLedger(ctx.portId, range),
        financialHasData(ctx.portId),
      ]);

      return NextResponse.json({
        data: {
          kpis,
          revenueByMonth,
          collectionFunnel,
          aging,
          cashFlow,
          expenseBreakdown,
          outstandingDeposits,
          recentPayments,
          refundLog,
          expenseLedger,
          hasData,
          range: { from: range.from.toISOString(), to: range.to.toISOString() },
        },
      });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
