import { NextResponse } from "next/server";
import { createClient } from "@/lib/supabase-server";
import { canCompany, getCompanyContext } from "@/lib/company-context";

function parseMonthRange(value: string) {
  if (!/^\d{4}-\d{2}$/.test(value)) return null;
  const [yearRaw, monthRaw] = value.split("-");
  const year = Number(yearRaw);
  const month = Number(monthRaw);
  if (!Number.isInteger(year) || !Number.isInteger(month)) return null;
  if (month < 1 || month > 12) return null;
  const start = new Date(Date.UTC(year, month - 1, 1, 0, 0, 0));
  const end = new Date(Date.UTC(year, month, 1, 0, 0, 0));
  return {
    start: start.toISOString().slice(0, 10),
    end: end.toISOString().slice(0, 10),
  };
}

function normalizeType(value: unknown): "IN" | "OUT" | null {
  if (typeof value !== "string") return null;
  const normalized = value.trim().toLowerCase();
  if (normalized === "in" || normalized === "entrada") return "IN";
  if (normalized === "out" || normalized === "saida" || normalized === "saída") return "OUT";
  return null;
}

const MANUAL_PREFIX = "[MANUAL] ";

function isManualTagged(description: unknown) {
  return typeof description === "string" && description.startsWith(MANUAL_PREFIX);
}

function normalizeOrigin(origin: unknown, description: unknown) {
  if (origin === "MANUAL") return "MANUAL";
  if (origin === "AJUSTE" && isManualTagged(description)) return "MANUAL";
  return typeof origin === "string" ? origin : "UNKNOWN";
}

function isRevenueRow(origin: unknown, type: "IN" | "OUT" | null) {
  return (origin === "PEDIDO" || origin === "RECEBER" || origin === "AJUSTE" || origin === "MANUAL") && type === "IN";
}

function isExpenseRow(origin: unknown, type: "IN" | "OUT" | null) {
  return (origin === "PAGAR" || origin === "AJUSTE" || origin === "MANUAL") && type === "OUT";
}

export async function GET(req: Request) {
  const supabase = await createClient();
  const {
    data: { user },
    error: userError,
  } = await supabase.auth.getUser();

  if (userError || !user) {
    return NextResponse.json({ error: "Não autenticado." }, { status: 401 });
  }

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "financial.cashflow.read")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

  const url = new URL(req.url);
  const month = url.searchParams.get("month")?.trim() ?? "";
  const bankAccountId = url.searchParams.get("bank_account_id")?.trim() ?? "";
  const monthRange = month ? parseMonthRange(month) : null;

  try {
    let query = supabase
      .from("cash_flow")
      .select("amount,type,origin,reference_id,description")
      .eq("company_id", ctx.companyId);

    if (monthRange) {
      query = query.gte("date", monthRange.start).lt("date", monthRange.end);
    }

    if (bankAccountId) {
      query = query.eq("bank_account_id", bankAccountId);
    }

    const { data, error } = await query;
    if (error) {
      throw error;
    }

    let rows = (data ?? []) as Array<{ amount: number | null; type: string | null; origin: string | null; reference_id?: string | null; description?: string | null }>;
    const pedidoReferenceIds = Array.from(
      new Set(
        rows
          .filter((row) => row.origin === "PEDIDO")
          .map((row) => row.reference_id)
          .filter((value): value is string => typeof value === "string" && value.length > 0)
      )
    );
    if (pedidoReferenceIds.length > 0) {
      const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [user.id];
      const { data: payments } = await supabase
        .from("payments")
        .select("id,order_id,user_id")
        .in("id", pedidoReferenceIds)
        .in("user_id", tenantIds);
      const paymentToOrder = new Map<string, string>();
      const orderIds = new Set<string>();
      (payments ?? []).forEach((payment) => {
        const id = (payment as { id?: string | null }).id;
        const orderId = (payment as { order_id?: string | null }).order_id;
        if (typeof id === "string" && typeof orderId === "string") {
          paymentToOrder.set(id, orderId);
          orderIds.add(orderId);
        }
      });
      if (orderIds.size > 0) {
        const { data: canceledOrders } = await supabase
          .from("orders")
          .select("id")
          .in("id", Array.from(orderIds))
          .in("user_id", tenantIds)
          .eq("status", "canceled");
        const canceledOrderSet = new Set((canceledOrders ?? []).map((row) => (row as { id: string }).id));
        rows = rows.filter((row) => {
          if (row.origin !== "PEDIDO") return true;
          const ref = row.reference_id;
          if (!ref) return true;
          const linkedOrderId = paymentToOrder.get(ref) || ref;
          return !canceledOrderSet.has(linkedOrderId);
        });
      }
    }

    const totals = rows.reduce(
      (acc, row) => {
        const amount = Number(row.amount ?? 0) || 0;
        const normalized = normalizeType(row.type);
        const normalizedOrigin = normalizeOrigin(row.origin, row.description);
        if (isRevenueRow(normalizedOrigin, normalized)) acc.totalIn += amount;
        if (isExpenseRow(normalizedOrigin, normalized)) acc.totalOut += amount;
        return acc;
      },
      { totalIn: 0, totalOut: 0 }
    );

    const totalIn = totals.totalIn;
    const totalOut = totals.totalOut;
    const netTotal = totalIn - totalOut;

    return NextResponse.json({
      ok: true,
      summary: {
        total_in: totalIn,
        total_out: totalOut,
        net_total: netTotal,
      },
    });
  } catch (error: unknown) {
    const err = error as { message?: string; details?: string; hint?: string; code?: string };
    return NextResponse.json(
      {
        error: "Falha ao carregar resumo do fluxo de caixa.",
        message: err?.message ?? null,
        details: err?.details ?? null,
        hint: err?.hint ?? null,
        code: err?.code ?? null,
      },
      { status: 500 }
    );
  }
}
