import type { FastifyInstance } from "fastify";
import { and, eq, gte, inArray, sql } from "drizzle-orm";
import { schema } from "@app/database";
import { requireActiveHousehold } from "../lib/helpers.js";

/** Budget & matsvinn (spec §26): vecka/månad, kostnad per måltid, svinnvärde. */
export async function budgetRoutes(app: FastifyInstance) {
  const auth = { preHandler: [app.authenticate] };

  app.get("/v1/budget/summary", auth, async (req) => {
    const householdId = await requireActiveHousehold(app.db, req.userId);
    const now = new Date();
    // UTC-kalender (samma policy som motorerna): identiska summor oavsett serverns tidszon.
    const mondayOffset = (now.getUTCDay() + 6) % 7; // 0 = måndag
    const weekStart = new Date(
      Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() - mondayOffset),
    );
    const monthStart = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));

    // Inköpskostnad = summa purchase-transaktioner med värde
    const [weekPurchases] = await app.db
      .select({ total: sql<number>`coalesce(sum(${schema.inventoryTransactions.valueMinor}), 0)` })
      .from(schema.inventoryTransactions)
      .where(
        and(
          eq(schema.inventoryTransactions.householdId, householdId),
          eq(schema.inventoryTransactions.type, "purchase"),
          gte(schema.inventoryTransactions.createdAt, weekStart),
        ),
      );
    const [monthPurchases] = await app.db
      .select({ total: sql<number>`coalesce(sum(${schema.inventoryTransactions.valueMinor}), 0)` })
      .from(schema.inventoryTransactions)
      .where(
        and(
          eq(schema.inventoryTransactions.householdId, householdId),
          eq(schema.inventoryTransactions.type, "purchase"),
          gte(schema.inventoryTransactions.createdAt, monthStart),
        ),
      );

    // Matsvinnsvärde = summa discard-transaktioner (spec §12, §26)
    const [weekWaste] = await app.db
      .select({
        total: sql<number>`coalesce(sum(${schema.inventoryTransactions.valueMinor}), 0)`,
        count: sql<number>`count(*)`,
      })
      .from(schema.inventoryTransactions)
      .where(
        and(
          eq(schema.inventoryTransactions.householdId, householdId),
          eq(schema.inventoryTransactions.type, "discard"),
          gte(schema.inventoryTransactions.createdAt, weekStart),
        ),
      );
    const [monthWaste] = await app.db
      .select({
        total: sql<number>`coalesce(sum(${schema.inventoryTransactions.valueMinor}), 0)`,
        count: sql<number>`count(*)`,
      })
      .from(schema.inventoryTransactions)
      .where(
        and(
          eq(schema.inventoryTransactions.householdId, householdId),
          eq(schema.inventoryTransactions.type, "discard"),
          gte(schema.inventoryTransactions.createdAt, monthStart),
        ),
      );

    // Kostnad per hemlagad måltid: lagade recept denna månad med kostnadsdata
    const cooks = await app.db
      .select({
        recipeId: schema.recipeCooks.recipeId,
        portions: schema.recipeCooks.portionsCooked,
      })
      .from(schema.recipeCooks)
      .where(
        and(
          eq(schema.recipeCooks.householdId, householdId),
          gte(schema.recipeCooks.cookedAt, monthStart),
        ),
      );
    let mealCostTotal = 0;
    let mealPortions = 0;
    if (cooks.length > 0) {
      const recipes = await app.db
        .select({ id: schema.recipes.id, cost: schema.recipes.estimatedCostMinorPerPortion })
        .from(schema.recipes)
        .where(inArray(schema.recipes.id, [...new Set(cooks.map((c) => c.recipeId))]));
      const costMap = new Map(recipes.map((r) => [r.id, r.cost]));
      for (const cook of cooks) {
        const cost = costMap.get(cook.recipeId);
        if (cost != null) {
          mealCostTotal += cost * cook.portions;
          mealPortions += cook.portions;
        }
      }
    }

    const [household] = await app.db
      .select({
        budget: schema.households.weeklyBudgetMinor,
        currencyCode: schema.households.currencyCode,
      })
      .from(schema.households)
      .where(eq(schema.households.id, householdId))
      .limit(1);

    // Alla belopp i minor units (heltal) i hushållets valuta (i18n-spec §20).
    const currency = household?.currencyCode ?? "SEK";
    return {
      currency,
      week: {
        purchasedMinor: Math.round(Number(weekPurchases?.total ?? 0)),
        wasteMinor: Math.round(Number(weekWaste?.total ?? 0)),
        wasteCount: Number(weekWaste?.count ?? 0),
        budgetMinor: household?.budget ?? null,
      },
      month: {
        purchasedMinor: Math.round(Number(monthPurchases?.total ?? 0)),
        wasteMinor: Math.round(Number(monthWaste?.total ?? 0)),
        wasteCount: Number(monthWaste?.count ?? 0),
        estimatedCostPerPortionMinor:
          mealPortions > 0 ? Math.round(mealCostTotal / mealPortions) : null,
        cookedPortions: mealPortions,
      },
      note: "Kostnader bygger på kvitton, angivna priser och schablonpriser – uppskattningar, inte bokföring.",
    };
  });
}
