import { Hono } from "hono";
import { recordAdminAuditLog } from "../helpers/adminAudit.js";
import {
  getAdminTableDefinition,
  listAdminTables,
  normalizeAdminRows,
} from "../helpers/adminRegistry.js";
import type { BaseEnv } from "../types/app.types.js";

export const getAdminTablesRouter = () => {
  const adminTablesRouter = new Hono<BaseEnv>();

  adminTablesRouter.get("/", async (c) => {
    return c.json({ tables: listAdminTables() }, 200);
  });

  adminTablesRouter.get("/:tableId/meta", async (c) => {
    const tableId = c.req.param("tableId");
    const tableDefinition = getAdminTableDefinition(tableId);

    if (!tableDefinition) {
      return c.json(
        {
          error: `Admin table '${tableId}' is not registered`,
        },
        404
      );
    }

    return c.json(
      {
        columns: tableDefinition.columns,
        editableFields: tableDefinition.editableColumns ?? [],
        id: tableDefinition.id,
        label: tableDefinition.label,
        primaryKey: tableDefinition.primaryKey,
      },
      200
    );
  });

  adminTablesRouter.get("/:tableId/rows", async (c) => {
    const supabase = c.get("supabase");
    const tableId = c.req.param("tableId");
    const tableDefinition = getAdminTableDefinition(tableId);

    if (!tableDefinition) {
      return c.json(
        {
          error: `Admin table '${tableId}' is not registered`,
        },
        404
      );
    }

    const { data, error } = await supabase
      .from(tableDefinition.source)
      .select(tableDefinition.select)
      .limit(50);

    if (error) {
      return c.json(
        {
          error: `Failed to load admin table '${tableId}'`,
        },
        500
      );
    }

    return c.json({ rows: normalizeAdminRows(data ?? []) }, 200);
  });

  adminTablesRouter.patch("/:tableId/rows/:rowId", async (c) => {
    const supabase = c.get("supabase");
    const adminSession = c.get("adminSession");
    const tableId = c.req.param("tableId");
    const rowId = c.req.param("rowId");
    const tableDefinition = getAdminTableDefinition(tableId);

    if (!tableDefinition) {
      return c.json(
        {
          error: `Admin table '${tableId}' is not registered`,
        },
        404
      );
    }

    const body = await c.req.json().catch(() => null);
    if (!body || typeof body !== "object") {
      return c.json({ error: "Invalid update payload" }, 400);
    }

    const requestedChanges = Object.fromEntries(
      Object.entries(body).filter(([key]) => tableDefinition.editableColumns?.includes(key))
    );

    if (Object.keys(requestedChanges).length === 0) {
      return c.json({ error: "No editable fields provided" }, 400);
    }

    const { data: existingRow, error: existingRowError } = await supabase
      .from(tableDefinition.source)
      .select(tableDefinition.select)
      .eq(tableDefinition.primaryKey, rowId)
      .single();

    if (existingRowError || !existingRow) {
      return c.json({ error: `Admin row '${rowId}' was not found` }, 404);
    }

    const { data: updatedRow, error: updateError } = await supabase
      .from(tableDefinition.source)
      .update(requestedChanges)
      .eq(tableDefinition.primaryKey, rowId)
      .select(tableDefinition.select)
      .single();

    if (updateError || !updatedRow) {
      return c.json({ error: `Failed to update admin table '${tableId}'` }, 500);
    }

    await recordAdminAuditLog({
      action: "update",
      after: updatedRow,
      before: existingRow,
      operatorEmail: adminSession.operatorEmail,
      operatorId: adminSession.operatorId,
      role: adminSession.role,
      supabase,
      targetId: rowId,
      targetType: tableId,
    });

    return c.json({ row: updatedRow }, 200);
  });

  return adminTablesRouter;
};
