import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono";
import { z } from "zod";
import { authMiddleware, requireAuth, type AuthVariables } from "../middleware/auth.middleware";
import { tenantMiddleware, requireHousehold, type TenantVariables } from "../middleware/tenant.middleware";
import {
  getCategoriesByHousehold,
  createCategory,
  updateCategory,
  deleteCategory,
} from "../services/category.service";
import { db, eq } from "@haushaltsApp/db";
import { categories } from "@haushaltsApp/db/schema";

type Variables = AuthVariables & TenantVariables;

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

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

const CreateCategorySchema = z.object({
  name: z.string().min(1),
  icon: z.string().nullable().optional(),
  color: z.string().nullable().optional(),
  type: z.enum(["income", "expense"]),
});

const UpdateCategorySchema = z.object({
  name: z.string().min(1).optional(),
  icon: z.string().nullable().optional(),
  color: z.string().nullable().optional(),
});

// GET /api/categories — list categories for household, optional ?type= filter
categoryRoutes.get("/", async (c) => {
  const householdId = c.get("householdId") as string;
  const typeFilter = c.req.query("type") as "income" | "expense" | undefined;
  let data = await getCategoriesByHousehold(householdId);
  if (typeFilter === "income" || typeFilter === "expense") {
    data = data.filter((cat) => cat.type === typeFilter);
  }
  return c.json({ categories: data });
});

// POST /api/categories — create category
categoryRoutes.post("/", zValidator("json", CreateCategorySchema), async (c) => {
  const householdId = c.get("householdId") as string;
  const input = c.req.valid("json");
  const cat = await createCategory(householdId, input);
  return c.json({ category: cat }, 201);
});

// PATCH /api/categories/:id — update category
categoryRoutes.patch("/:id", zValidator("json", UpdateCategorySchema), async (c) => {
  const householdId = c.get("householdId") as string;
  const { id } = c.req.param();
  const input = c.req.valid("json");
  const cat = await updateCategory(householdId, id, input);
  if (!cat) return c.json({ error: "Not found" }, 404);
  return c.json({ category: cat });
});

// DELETE /api/categories/:id — delete category
categoryRoutes.delete("/:id", async (c) => {
  const householdId = c.get("householdId") as string;
  const { id } = c.req.param();

  // Check if category is a default category
  const [existing] = await db
    .select()
    .from(categories)
    .where(eq(categories.id, id));

  if (!existing || existing.householdId !== householdId) {
    return c.json({ error: "Not found" }, 404);
  }

  if (existing.isDefault) {
    return c.json(
      { error: "Standardkategorien können nicht gelöscht werden", usageCount: 0 },
      409
    );
  }

  const result = await deleteCategory(householdId, id);
  if (!result.deleted) {
    return c.json(
      {
        error: `${result.usageCount} Buchungen verwenden diese Kategorie`,
        usageCount: result.usageCount,
      },
      409
    );
  }
  return c.json({ deleted: true });
});
