import { badRequest } from "@infra/errors";
import { asyncRoute, fail, ok } from "@infra/http";
import { DEFAULT_JOB_OWNER_PROFILE_ID } from "@server/infra/job-owner-context";
import { getJobOwnerProfileId } from "@server/infra/request-context";
import * as keywordSetsRepo from "@server/repositories/keyword-sets";
import { type Request, type Response, Router } from "express";
import { z } from "zod";

export const keywordSetsRouter = Router();

const termsSchema = z
  .array(z.string().trim().min(1).max(200))
  .max(100)
  .optional();

const createSchema = z.object({
  name: z.string().trim().min(1).max(100),
  terms: termsSchema,
});

const updateSchema = z.object({
  name: z.string().trim().min(1).max(100).optional(),
  terms: termsSchema,
});

function resolveOwnerProfileId(): string {
  const fromContext = getJobOwnerProfileId();
  if (fromContext && fromContext !== "__unmapped__") {
    return fromContext;
  }
  return DEFAULT_JOB_OWNER_PROFILE_ID;
}

function handleRepoError(res: Response, error: unknown) {
  const message = error instanceof Error ? error.message : String(error);
  if (/maximum of/i.test(message) || /cannot delete/i.test(message)) {
    return fail(res, badRequest(message));
  }
  throw error;
}

keywordSetsRouter.get(
  "/",
  asyncRoute(async (_req: Request, res: Response) => {
    const ownerProfileId = resolveOwnerProfileId();
    const sets = await keywordSetsRepo.listKeywordSets(ownerProfileId);
    return ok(res, sets);
  }),
);

keywordSetsRouter.post(
  "/",
  asyncRoute(async (req: Request, res: Response) => {
    const parsed = createSchema.safeParse(req.body);
    if (!parsed.success) {
      throw badRequest("Invalid keyword set payload", {
        issues: parsed.error.issues,
      });
    }
    const ownerProfileId = resolveOwnerProfileId();
    try {
      const created = await keywordSetsRepo.createKeywordSet(
        ownerProfileId,
        parsed.data,
      );
      return ok(res, created);
    } catch (error) {
      return handleRepoError(res, error);
    }
  }),
);

keywordSetsRouter.patch(
  "/:id",
  asyncRoute(async (req: Request, res: Response) => {
    const parsed = updateSchema.safeParse(req.body);
    if (!parsed.success) {
      throw badRequest("Invalid keyword set payload", {
        issues: parsed.error.issues,
      });
    }
    const ownerProfileId = resolveOwnerProfileId();
    const updated = await keywordSetsRepo.updateKeywordSet(
      req.params.id,
      ownerProfileId,
      parsed.data,
    );
    if (!updated) {
      return fail(res, badRequest("Keyword set not found"));
    }
    return ok(res, updated);
  }),
);

keywordSetsRouter.delete(
  "/:id",
  asyncRoute(async (req: Request, res: Response) => {
    const ownerProfileId = resolveOwnerProfileId();
    try {
      const deleted = await keywordSetsRepo.deleteKeywordSet(
        req.params.id,
        ownerProfileId,
      );
      if (!deleted) {
        return fail(res, badRequest("Keyword set not found"));
      }
      return ok(res, { deleted: true });
    } catch (error) {
      return handleRepoError(res, error);
    }
  }),
);

keywordSetsRouter.post(
  "/:id/activate",
  asyncRoute(async (req: Request, res: Response) => {
    const ownerProfileId = resolveOwnerProfileId();
    const activated = await keywordSetsRepo.activateKeywordSet(
      req.params.id,
      ownerProfileId,
    );
    if (!activated) {
      return fail(res, badRequest("Keyword set not found"));
    }
    return ok(res, activated);
  }),
);
