import { logger } from "@infra/logger";
import type { JobSearchProfile } from "@shared/types";
import { LlmService } from "./llm/service";
import type { JsonSchemaDefinition } from "./llm/types";
import { resolveLlmModel } from "./modelSelection";
import { sanitizeProfileForPrompt } from "./scorer";

const PROFILE_GENERATION_SCHEMA: JsonSchemaDefinition = {
  name: "job_search_profile",
  schema: {
    type: "object",
    properties: {
      targetRoles: {
        type: "array",
        items: { type: "string" },
        description:
          "3-8 job titles the candidate would be a good fit for, based on their experience",
      },
      experienceLevel: {
        type: "string",
        description:
          "Experience level (e.g. 'Junior', 'Mid-level', 'Senior', 'Lead', 'Principal')",
      },
      mustHaveSkills: {
        type: "array",
        items: { type: "string" },
        description:
          "Core technical and professional skills evident from the resume",
      },
      niceToHaveSkills: {
        type: "array",
        items: { type: "string" },
        description: "Secondary skills or technologies mentioned in the resume",
      },
      dealBreakers: {
        type: "array",
        items: { type: "string" },
        description:
          "Types of roles that would NOT match this candidate (inferred from their specialisation)",
      },
      preferredWorkArrangement: {
        type: "array",
        items: { type: "string" },
        description: "Work arrangement preferences (remote, hybrid, onsite)",
      },
      preferredLocations: {
        type: "array",
        items: { type: "string" },
        description: "Locations inferred from resume (current city, country)",
      },
      minimumSalary: {
        type: "string",
        description: "Leave empty string — cannot be inferred from a resume",
      },
      industriesToTarget: {
        type: "array",
        items: { type: "string" },
        description: "Industries that match the candidate's experience",
      },
      industriesToAvoid: {
        type: "array",
        items: { type: "string" },
        description:
          "Industries that clearly don't match (leave empty if unclear)",
      },
      aboutMe: {
        type: "string",
        description:
          "A 2-3 sentence summary of who this person is and what they're looking for, written in first person",
      },
    },
    required: [
      "targetRoles",
      "experienceLevel",
      "mustHaveSkills",
      "niceToHaveSkills",
      "dealBreakers",
      "preferredWorkArrangement",
      "preferredLocations",
      "minimumSalary",
      "industriesToTarget",
      "industriesToAvoid",
      "aboutMe",
    ],
    additionalProperties: false,
  },
};

function buildGenerationPrompt(resumeProfile: Record<string, unknown>): string {
  const parts: string[] = [];

  parts.push(
    "Analyse this resume and create a job search profile for the candidate.",
  );
  parts.push("");
  parts.push("RULES:");
  parts.push(
    "- Infer target roles from their actual job titles and experience, not aspirational ones",
  );
  parts.push(
    "- Extract real skills from the resume — do not invent skills not evidenced",
  );
  parts.push(
    "- For deal-breakers, think about what kinds of roles would be a BAD match",
  );
  parts.push(
    "  (e.g. if they're an automation tester, 'Full-stack development roles' is a deal-breaker)",
  );
  parts.push("- Infer location from resume if available");
  parts.push("- Leave minimumSalary as empty string (cannot be inferred)");
  parts.push(
    "- Write aboutMe in first person as if the candidate is describing themselves",
  );
  parts.push("- Be specific and practical, not generic");
  parts.push("");
  parts.push("=== RESUME ===");
  parts.push(JSON.stringify(resumeProfile, null, 2));

  return parts.join("\n");
}

export async function generateProfileFromResume(
  resumeProfile: Record<string, unknown>,
): Promise<JobSearchProfile> {
  const model = await resolveLlmModel("scoring");

  const prompt = buildGenerationPrompt(sanitizeProfileForPrompt(resumeProfile));

  const llm = new LlmService();
  const result = await llm.callJson<JobSearchProfile>({
    model,
    messages: [{ role: "user", content: prompt }],
    jsonSchema: PROFILE_GENERATION_SCHEMA,
    maxRetries: 1,
  });

  if (!result.success) {
    logger.error("Profile generation from resume failed", {
      error: result.error,
    });
    throw new Error(`Profile generation failed: ${result.error}`);
  }

  const data = result.data;

  return {
    targetRoles: Array.isArray(data.targetRoles) ? data.targetRoles : [],
    experienceLevel:
      typeof data.experienceLevel === "string" ? data.experienceLevel : "",
    mustHaveSkills: Array.isArray(data.mustHaveSkills)
      ? data.mustHaveSkills
      : [],
    niceToHaveSkills: Array.isArray(data.niceToHaveSkills)
      ? data.niceToHaveSkills
      : [],
    dealBreakers: Array.isArray(data.dealBreakers) ? data.dealBreakers : [],
    preferredWorkArrangement: Array.isArray(data.preferredWorkArrangement)
      ? data.preferredWorkArrangement
      : [],
    preferredLocations: Array.isArray(data.preferredLocations)
      ? data.preferredLocations
      : [],
    minimumSalary:
      typeof data.minimumSalary === "string" ? data.minimumSalary : "",
    industriesToTarget: Array.isArray(data.industriesToTarget)
      ? data.industriesToTarget
      : [],
    industriesToAvoid: Array.isArray(data.industriesToAvoid)
      ? data.industriesToAvoid
      : [],
    aboutMe: typeof data.aboutMe === "string" ? data.aboutMe : "",
  };
}
