import { Hono } from "hono";
import type { Context } from "hono";
import { apiKeyAuth } from "@/middlewares/apiKeyAuth";
import { logError } from "@/lib/logger";
import { EDMService } from "@/v1/services/admin/edm/edm.service";
import {
  browseEDMFolderHandler,
  scanEDMImagesHandler,
  uploadEDMAssetHandler,
  deleteEDMAssetHandler,
} from "@/controllers/admin/edm/edm-workflow.controller";
import {
  createEDMHandler,
  updateEDMHandler,
} from "@/controllers/admin/edm/edm.controller";

/**
 * Service-to-service EDM template fetch.
 *
 * Called by the SMTP worker in the main core (karma-subito), which renders the
 * returned Handlebars itself and sends the result as raw html — SendGrid stops
 * being the template store and stays only the transport.
 *
 * Mounted OUTSIDE /v1/admin-console on purpose: those routes sit behind
 * withConsoleUserSession(), and the worker has no console session. Auth here is
 * the pre-existing apiKeyAuth() (an AES-256-GCM x-api-payload header with a
 * 60-second window), which until now was defined but mounted nowhere.
 *
 * 404 is a meaningful response, not just an error: it is the worker's signal
 * that this template has not been migrated yet and it should fall back to
 * sending via SendGrid's template_id.
 */
export const EDMInternalRoutes = new Hono();

EDMInternalRoutes.use("*", apiKeyAuth());

EDMInternalRoutes.get("/templates/:templateId", async (c: Context) => {
  try {
    const db = c.get("datastore");
    const templateId = c.req.param("templateId");
    if (!templateId) {
      return c.json({ success: false, message: "templateId is required" }, 400);
    }

    const result = await EDMService.getInstance().getRenderableTemplate(db, templateId);

    if (!result.success) {
      /**
       * SendGrid fallback, ON by default. `?fallback=none` opts out.
       *
       * Gives the routing the ids imply, without anyone having to check a
       * prefix:
       *
       *   k-…  ours, found locally           → GCS
       *   d-…  SendGrid's, not found locally → SendGrid
       *
       * Deliberately NOT implemented as `if (id.startsWith("d-"))`. A prefix
       * says where an id came FROM, not where it lives now: the backfill
       * mirrors SendGrid templates into GCS and keeps their d- id, which is
       * exactly what makes the migration a zero-rewrite change. Prefix routing
       * would send every backfilled template to SendGrid forever and serve
       * stale html the moment someone edited it here.
       *
       * Looking locally first and falling back gives today's behaviour and
       * stays correct after a backfill, with no code change.
       *
       * The SMTP worker must opt out with `?fallback=none`: for it a 404 means
       * "not ours, send with SendGrid's own template_id", and letting it render
       * SendGrid's html locally is the behaviour change the staged rollout
       * exists to avoid.
       */
      const wantsFallback = !["none", "0", "false"].includes(
        (c.req.query("fallback") ?? "").toLowerCase(),
      );

      if (wantsFallback && result.status === 404) {
        const remote = await EDMService.getInstance().getTemplate(db, templateId);
        if (remote.success) {
          const version =
            remote.data.versions?.find((v) => v.active === 1) ??
            remote.data.versions?.[0];

          if (version?.html_content) {
            return c.json({
              success: true,
              data: {
                templateId,
                versionId: version.id ?? null,
                subject: version.subject ?? "",
                html: version.html_content,
                plain: version.plain_content ?? "",
                generatePlain: version.generate_plain_content ?? true,
                // So a caller can tell which store answered without diffing ids.
                source: "sendgrid",
              },
            });
          }
        }
      }

      return c.json({ success: false, message: result.message }, result.status as 404 | 500);
    }

    return c.json({
      success: true,
      data: {
        templateId: result.data.templateId,
        versionId: result.data.versionId,
        // Handlebars source, not rendered output — the worker merges per
        // recipient. Subject is included because nothing upstream of the
        // worker supplies one.
        subject: result.data.subject,
        html: result.data.html,
        plain: result.data.plain,
        generatePlain: result.data.generatePlain,
        source: "local",
      },
    });
  } catch (err: any) {
    logError(err, "[EDM] internal template fetch failed");
    return c.json(
      { success: false, message: err?.message ?? "Failed to fetch EDM template" },
      500,
    );
  }
});

/**
 * ── Editor-facing endpoints ──────────────────────────────────────────────────
 *
 * Everything below exists so the VS Code extension can authenticate with the
 * shared API key instead of a pasted console session cookie.
 *
 * The trade being made, stated once: apiKeyAuth grants full trust and has no
 * per-user revocation, so the key on a developer's laptop is the same key the
 * SMTP worker uses. Losing a laptop means rotating it everywhere. The
 * alternative — per-user personal access tokens — does not exist yet and is
 * tracked separately.
 *
 * These mirror the /v1/admin-console/edm handlers rather than replacing them:
 * the console keeps using session auth, and RBAC there is unchanged.
 */

/** Full template list, same shape the console list page consumes. */
EDMInternalRoutes.get("/templates", async (c: Context) => {
  try {
    const db = c.get("datastore");
    const result = await EDMService.getInstance().listTemplates(db);
    if (!result.success) {
      return c.json({ success: false, message: result.message }, 502);
    }
    return c.json({ success: true, data: result.data });
  } catch (err: any) {
    logError(err, "[EDM] internal list failed");
    return c.json({ success: false, message: err?.message ?? "Failed" }, 500);
  }
});

/**
 * The full template record including html, as opposed to /templates/:id which
 * returns only the active version's renderable source for the mail worker.
 */
EDMInternalRoutes.get("/templates/:templateId/full", async (c: Context) => {
  try {
    const db = c.get("datastore");
    const templateId = c.req.param("templateId");
    if (!templateId) {
      return c.json({ success: false, message: "templateId is required" }, 400);
    }

    const result = await EDMService.getInstance().getTemplate(db, templateId);
    if (!result.success) {
      const status = (result as { status?: number }).status === 404 ? 404 : 502;
      return c.json({ success: false, message: result.message }, status);
    }
    return c.json({ success: true, data: result.data });
  } catch (err: any) {
    logError(err, "[EDM] internal get full failed");
    return c.json({ success: false, message: err?.message ?? "Failed" }, 500);
  }
});

/** One folder's contents — drives the editor's tree view. */
EDMInternalRoutes.get("/browse", browseEDMFolderHandler);

/** Preflight. Pure analysis, writes nothing. */
EDMInternalRoutes.post("/scan", scanEDMImagesHandler);

/** Upload one image. Writes to the public asset bucket. */
EDMInternalRoutes.post("/assets", uploadEDMAssetHandler);
EDMInternalRoutes.delete("/assets", deleteEDMAssetHandler);

/** Create a template. */
EDMInternalRoutes.post("/templates", createEDMHandler);

/** Update a template — appends a new version, never mutates one. */
EDMInternalRoutes.patch("/templates/:templateId", updateEDMHandler);
