import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono";
import { authMiddleware, requireAuth, type AuthVariables } from "../middleware/auth.middleware";
import { requireHousehold, tenantMiddleware, type TenantVariables } from "../middleware/tenant.middleware";
import {
  activateFixedTransactions,
  carryOverBalance,
  createTransaction,
  deleteTransaction,
  getTransactionById,
  getTransactions,
  getTransactionSummary,
  updateTransaction,
} from "../services/transaction.service";
import {
  CreateTransactionSchema,
  TransactionFiltersSchema,
  UpdateTransactionSchema,
} from "@haushaltsApp/shared/schemas/transaction";

type Variables = AuthVariables & TenantVariables;

export const transactionRoutes = new Hono<{ Variables: Variables }>();

transactionRoutes.use("/*", authMiddleware, requireAuth, tenantMiddleware, requireHousehold);

transactionRoutes.get(
  "/",
  zValidator("query", TransactionFiltersSchema),
  async (c) => {
    const householdId = c.get("householdId") as string;
    const user = c.get("user") as { id: string };
    const filters = c.req.valid("query");
    const data = await getTransactions(householdId, user.id, filters);
    return c.json({ transactions: data });
  },
);

transactionRoutes.get("/summary", async (c) => {
  const householdId = c.get("householdId") as string;
  const user = c.get("user") as { id: string };
  const monthParam = c.req.query("month");
  const scope = c.req.query("scope") as "household" | "private" | "child" | undefined;
  const month = monthParam ? new Date(monthParam) : new Date();
  const summary = await getTransactionSummary(householdId, user.id, month, scope);
  return c.json(summary);
});

// POST /api/transactions/activate-fixed
transactionRoutes.post("/activate-fixed", async (c) => {
  const householdId = c.get("householdId") as string;
  const user = c.get("user") as { id: string };
  const body = await c.req.json<{ month: string; scope: "household" | "private" | "child"; childId?: string }>();
  const result = await activateFixedTransactions(householdId, user.id, body.month, body.scope, body.childId);
  return c.json(result);
});

// POST /api/transactions/carry-over
transactionRoutes.post("/carry-over", async (c) => {
  const householdId = c.get("householdId") as string;
  const user = c.get("user") as { id: string };
  const body = await c.req.json<{
    fromMonth: string;
    toMonth: string;
    scope: "household" | "private" | "child";
    childId?: string;
  }>();

  const result = await carryOverBalance(householdId, user.id, body.fromMonth, body.toMonth, body.scope, body.childId);
  if (result.alreadyExists) {
    return c.json({ error: "Für diesen Monat gibt es bereits einen Übertrag" }, 409);
  }
  if (!result.transaction) {
    return c.json({ error: "Saldo ist ausgeglichen — kein Übertrag nötig" }, 422);
  }
  return c.json({ transaction: result.transaction }, 201);
});

transactionRoutes.get("/:id", async (c) => {
  const householdId = c.get("householdId") as string;
  const { id } = c.req.param();
  const transaction = await getTransactionById(id, householdId);
  if (!transaction) return c.json({ error: "Not found" }, 404);
  return c.json({ transaction });
});

transactionRoutes.post(
  "/",
  zValidator("json", CreateTransactionSchema),
  async (c) => {
    const householdId = c.get("householdId") as string;
    const user = c.get("user") as { id: string };
    const input = c.req.valid("json");
    const transaction = await createTransaction(householdId, user.id, input);
    return c.json({ transaction }, 201);
  },
);

transactionRoutes.patch(
  "/:id",
  zValidator("json", UpdateTransactionSchema),
  async (c) => {
    const householdId = c.get("householdId") as string;
    const { id } = c.req.param();
    const input = c.req.valid("json");
    const transaction = await updateTransaction(id, householdId, input);
    if (!transaction) return c.json({ error: "Not found" }, 404);
    return c.json({ transaction });
  },
);

transactionRoutes.delete("/:id", async (c) => {
  const householdId = c.get("householdId") as string;
  const { id } = c.req.param();
  const transaction = await deleteTransaction(id, householdId);
  if (!transaction) return c.json({ error: "Not found" }, 404);
  return c.json({ transaction });
});
