import { readFile, stat } from "node:fs/promises";
import path from "node:path";
import { logger } from "@infra/logger";
import { getSetting } from "@server/repositories/settings";
import type { ResumeProfile } from "@shared/types";
import { getResume, RxResumeAuthConfigError } from "./rxresume";
import { getConfiguredRxResumeBaseResumeId } from "./rxresume/baseResumeId";

let cachedProfile: ResumeProfile | null = null;
let cachedResumeId: string | null = null;

/** Cache key is absolute path + file mtime (ms). */
let cachedLocalSourceKey: string | null = null;
let cachedLocalProfile: ResumeProfile | null = null;

/**
 * Prefer `JOBOPS_LOCAL_RESUME_PATH`, then `localResumeProfilePath` setting.
 * Relative paths resolve against `process.cwd()` (orchestrator working directory).
 */
export async function resolveLocalResumeFilePath(): Promise<string | null> {
  const envPath = process.env.JOBOPS_LOCAL_RESUME_PATH?.trim();
  const raw = envPath ?? (await getSetting("localResumeProfilePath"))?.trim();
  if (!raw) return null;
  return path.isAbsolute(raw) ? raw : path.resolve(process.cwd(), raw);
}

async function loadProfileFromLocalFile(
  absolutePath: string,
  forceRefresh: boolean,
): Promise<ResumeProfile> {
  let mtimeKey = "unknown";
  try {
    const st = await stat(absolutePath);
    mtimeKey = String(st.mtimeMs);
  } catch {
    mtimeKey = "missing";
  }
  const cacheKey = `${absolutePath}:${mtimeKey}`;

  if (
    !forceRefresh &&
    cacheKey === cachedLocalSourceKey &&
    cachedLocalProfile !== null
  ) {
    return cachedLocalProfile;
  }

  let raw: string;
  try {
    raw = await readFile(absolutePath, "utf8");
  } catch (error) {
    const detail = error instanceof Error ? error.message : "Unknown error";
    throw new Error(
      `Cannot read local resume file at ${absolutePath}. ${detail}`,
    );
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(raw);
  } catch {
    throw new Error(
      `Local resume file at ${absolutePath} is not valid JSON (Reactive Resume export shape expected).`,
    );
  }

  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
    throw new Error(
      `Local resume file at ${absolutePath} must be a single JSON object.`,
    );
  }

  cachedLocalSourceKey = cacheKey;
  cachedLocalProfile = parsed as ResumeProfile;
  logger.info("Profile loaded from local JSON file", {
    path: absolutePath,
  });
  return cachedLocalProfile;
}

/**
 * Get the base resume profile: local JSON file (if configured) first, else Reactive Resume API.
 *
 * Local sources (in order): `JOBOPS_LOCAL_RESUME_PATH` env, then `localResumeProfilePath` setting.
 * Otherwise requires `rxresumeBaseResumeId` and RxResume credentials.
 *
 * Results are cached until clearProfileCache() is called.
 *
 * @param forceRefresh Force reload from disk or API.
 */
export async function getProfile(forceRefresh = false): Promise<ResumeProfile> {
  const localPath = await resolveLocalResumeFilePath();
  if (localPath) {
    return loadProfileFromLocalFile(localPath, forceRefresh);
  }

  const { resumeId: rxresumeBaseResumeId } =
    await getConfiguredRxResumeBaseResumeId();

  if (!rxresumeBaseResumeId) {
    throw new Error(
      "Base resume not configured. Set JOBOPS_LOCAL_RESUME_PATH or local resume path in Settings, or select a base resume from Reactive Resume.",
    );
  }

  // Return cached profile if valid
  if (
    cachedProfile &&
    cachedResumeId === rxresumeBaseResumeId &&
    !forceRefresh
  ) {
    return cachedProfile;
  }

  try {
    logger.info("Fetching profile from Reactive Resume", {
      resumeId: rxresumeBaseResumeId,
    });
    const resume = forceRefresh
      ? await getResume(rxresumeBaseResumeId, { forceRefresh: true })
      : await getResume(rxresumeBaseResumeId);

    if (!resume.data || typeof resume.data !== "object") {
      throw new Error("Resume data is empty or invalid");
    }

    cachedProfile = resume.data as unknown as ResumeProfile;
    cachedResumeId = rxresumeBaseResumeId;
    logger.info("Profile loaded from Reactive Resume", {
      resumeId: rxresumeBaseResumeId,
    });
    return cachedProfile;
  } catch (error) {
    if (error instanceof RxResumeAuthConfigError) {
      throw new Error(error.message);
    }
    logger.error("Failed to load profile from Reactive Resume", {
      resumeId: rxresumeBaseResumeId,
      error,
    });
    throw error;
  }
}

/**
 * Get the person's name from the profile.
 */
export async function getPersonName(): Promise<string> {
  const profile = await getProfile();
  return profile?.basics?.name || "Resume";
}

/**
 * Clear the profile cache.
 */
export function clearProfileCache(): void {
  cachedProfile = null;
  cachedResumeId = null;
  cachedLocalSourceKey = null;
  cachedLocalProfile = null;
}
