import { Router } from "express";
import type { Db } from "@paperclipai/db";
import type { StorageService } from "../storage/types.js";
import { contentJobStore } from "../services/content-job-store.js";
import { contentJobRunner } from "../services/content-job-runner.js";
import { subscribeCompanyLiveEvents } from "../services/live-events.js";
import { assertCompanyAccess } from "./authz.js";

export function contentJobRoutes(db: Db, storage: StorageService) {
  const router = Router();

  // POST /companies/:companyId/content-jobs — submit a new content generation job
  router.post("/companies/:companyId/content-jobs", async (req, res) => {
    const companyId = req.params.companyId!;
    assertCompanyAccess(req, companyId);

    const { jobType, input, sourceTaskId } = req.body as {
      jobType?: unknown;
      input?: unknown;
      sourceTaskId?: unknown;
    };

    if (!jobType || typeof jobType !== "string" || jobType.trim() === "") {
      res.status(400).json({ error: "jobType is required" });
      return;
    }

    const store = contentJobStore(db);
    const job = await store.create(companyId, {
      jobType,
      input: (typeof input === "object" && input !== null && !Array.isArray(input))
        ? (input as Record<string, unknown>)
        : {},
      sourceTaskId: typeof sourceTaskId === "string" ? sourceTaskId : null,
    });

    void contentJobRunner.dispatch(db, storage, job!);

    res.status(202).json({
      jobId: job!.id,
      status: job!.status,
      createdAt: job!.createdAt,
    });
  });

  // GET /companies/:companyId/content-jobs — list all jobs for a company
  router.get("/companies/:companyId/content-jobs", async (req, res) => {
    const companyId = req.params.companyId!;
    assertCompanyAccess(req, companyId);

    const jobs = await contentJobStore(db).listByCompany(companyId);
    res.json(jobs);
  });

  // GET /companies/:companyId/content-jobs/:jobId — retrieve a single job
  router.get("/companies/:companyId/content-jobs/:jobId", async (req, res) => {
    const companyId = req.params.companyId!;
    assertCompanyAccess(req, companyId);

    const job = await contentJobStore(db).getById(req.params.jobId!);
    if (!job) {
      res.status(404).json({ error: "Job not found" });
      return;
    }
    res.json(job);
  });

  // GET /companies/:companyId/content-jobs/:jobId/events — SSE progress stream
  router.get("/companies/:companyId/content-jobs/:jobId/events", async (req, res) => {
    const companyId = req.params.companyId!;
    assertCompanyAccess(req, companyId);

    res.setHeader("Content-Type", "text/event-stream");
    res.setHeader("Cache-Control", "no-cache");
    res.setHeader("Connection", "keep-alive");
    res.flushHeaders();

    const sendEvent = (type: string, data: unknown) => {
      res.write(`event: ${type}\ndata: ${JSON.stringify(data)}\n\n`);
    };

    const job = await contentJobStore(db).getById(req.params.jobId!);
    if (!job) {
      sendEvent("error", { error: "Job not found" });
      res.end();
      return;
    }

    sendEvent("status", {
      jobId: job.id,
      status: job.status,
      resultAssetId: job.resultAssetId,
      errorMessage: job.errorMessage,
    });

    if (job.status === "done" || job.status === "failed") {
      res.end();
      return;
    }

    const jobId = req.params.jobId!;
    const unsubscribe = subscribeCompanyLiveEvents(companyId, (event) => {
      if (
        event.type.startsWith("content_job.") &&
        (event.payload as Record<string, unknown>).jobId === jobId
      ) {
        sendEvent("status", event.payload);
        if (event.type === "content_job.done" || event.type === "content_job.failed") {
          unsubscribe();
          res.end();
        }
      }
    });

    req.on("close", () => {
      unsubscribe();
    });
  });

  return router;
}
