import { BlueprintTarget, PermissionKey } from "@capakraken/shared";
import type { BlueprintFieldDefinition } from "@capakraken/shared";
import { z } from "zod";
import { controllerProcedure, createTRPCRouter, managerProcedure, requirePermission } from "../trpc.js";

export const importExportRouter = createTRPCRouter({
  /**
   * Export resources as CSV.
   */
  exportResourcesCSV: controllerProcedure.query(async ({ ctx }) => {
    const [resources, globalBlueprints] = await Promise.all([
      ctx.db.resource.findMany({
        where: { isActive: true },
        orderBy: { eid: "asc" },
      }),
      ctx.db.blueprint.findMany({
        where: { target: BlueprintTarget.RESOURCE, isGlobal: true, isActive: true },
        select: { fieldDefs: true },
      }),
    ]);

    // Collect all custom field defs that should appear in exports (showInList = true)
    const customDefs = globalBlueprints
      .flatMap((b) => b.fieldDefs as unknown as BlueprintFieldDefinition[])
      .filter((f) => f.showInList);

    function escapeCSV(v: unknown): string {
      const s = v === null || v === undefined ? "" : String(v);
      return s.includes(",") || s.includes('"') || s.includes("\n")
        ? `"${s.replace(/"/g, '""')}"`
        : s;
    }

    const builtinHeaders = ["eid", "displayName", "email", "chapter", "lcrCents", "ucrCents", "currency", "chargeabilityTarget"];
    const customHeaders = customDefs.map((f) => f.label);
    const headers = [...builtinHeaders, ...customHeaders];

    const rows = resources.map((r) => {
      const df = r.dynamicFields as unknown as Record<string, unknown> ?? {};
      const builtins = [r.eid, r.displayName, r.email, r.chapter ?? "", r.lcrCents, r.ucrCents, r.currency, r.chargeabilityTarget];
      const customs = customDefs.map((f) => df[f.key] ?? "");
      return [...builtins, ...customs].map(escapeCSV).join(",");
    });

    return [headers.map(escapeCSV).join(","), ...rows].join("\n");
  }),

  /**
   * Export projects as CSV.
   */
  exportProjectsCSV: controllerProcedure.query(async ({ ctx }) => {
    const [projects, globalBlueprints] = await Promise.all([
      ctx.db.project.findMany({ orderBy: { shortCode: "asc" } }),
      ctx.db.blueprint.findMany({
        where: { target: BlueprintTarget.PROJECT, isGlobal: true, isActive: true },
        select: { fieldDefs: true },
      }),
    ]);

    const customDefs = globalBlueprints
      .flatMap((b) => b.fieldDefs as unknown as BlueprintFieldDefinition[])
      .filter((f) => f.showInList);

    function escapeCSV(v: unknown): string {
      const s = v === null || v === undefined ? "" : String(v);
      return s.includes(",") || s.includes('"') || s.includes("\n")
        ? `"${s.replace(/"/g, '""')}"`
        : s;
    }

    const builtinHeaders = ["shortCode", "name", "orderType", "status", "budgetCents", "startDate", "endDate", "winProbability"];
    const headers = [...builtinHeaders, ...customDefs.map((f) => f.label)];

    const rows = projects.map((p) => {
      const df = p.dynamicFields as unknown as Record<string, unknown> ?? {};
      const builtins = [
        p.shortCode, p.name, p.orderType, p.status, p.budgetCents,
        p.startDate.toISOString().split("T")[0],
        p.endDate.toISOString().split("T")[0],
        p.winProbability,
      ];
      return [...builtins, ...customDefs.map((f) => df[f.key] ?? "")].map(escapeCSV).join(",");
    });

    return [headers.map(escapeCSV).join(","), ...rows].join("\n");
  }),

  /**
   * Import resources from CSV data (parsed client-side).
   */
  importCSV: managerProcedure
    .input(
      z.object({
        entityType: z.enum(["resources", "projects", "allocations"]),
        rows: z.array(z.record(z.string(), z.string())),
        dryRun: z.boolean().default(true),
      }),
    )
    .mutation(async ({ ctx, input }) => {
      requirePermission(ctx, PermissionKey.IMPORT_DATA);
      const { entityType, rows, dryRun } = input;
      const results = {
        total: rows.length,
        created: 0,
        updated: 0,
        errors: [] as { row: number; message: string }[],
        dryRun,
      };

      if (dryRun) {
        // Validate without committing
        return { ...results, message: `Dry run: ${rows.length} rows validated` };
      }

      // Basic import logic per entity type
      for (let i = 0; i < rows.length; i++) {
        const row = rows[i];
        if (!row) continue;

        try {
          if (entityType === "resources") {
            const existing = await ctx.db.resource.findFirst({
              where: { eid: row["eid"] ?? "" },
            });

            if (existing) {
              await ctx.db.resource.update({
                where: { id: existing.id },
                data: {
                  displayName: row["displayName"] ?? existing.displayName,
                  email: row["email"] ?? existing.email,
                  chapter: row["chapter"] ?? existing.chapter,
                  lcrCents: row["lcrCents"] ? parseInt(row["lcrCents"]) : existing.lcrCents,
                },
              });
              results.updated++;
            } else {
              results.errors.push({ row: i + 1, message: "New resource creation via import requires full data" });
            }
          }
        } catch (err) {
          results.errors.push({ row: i + 1, message: err instanceof Error ? err.message : "Unknown error" });
        }
      }

      await ctx.db.auditLog.create({
        data: {
          entityType: entityType,
          entityId: "bulk-import",
          action: "IMPORT",
          changes: { summary: results },
        },
      });

      return results;
    }),
});
