import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { MEMORY } from "@/core/constants.js";

export interface PrMemoryEntry {
  commentId: number;
  commentAuthor: string;
  commentBody: string;
  agentReply: string;
  filesChanged: string[];
  timestamp: string;
}

export function buildPrMemoryKey(repoName: string, prNumber: number): string {
  return `${repoName}#${prNumber}`;
}

export function loadPrMemory(key: string): PrMemoryEntry[] {
  const filePath = getMemoryPath(key);
  if (!existsSync(filePath)) return [];

  try {
    const parsed = JSON.parse(readFileSync(filePath, "utf-8")) as unknown;
    return Array.isArray(parsed) ? parsed.filter(isPrMemoryEntry) : [];
  } catch {
    return [];
  }
}

export function appendPrMemory(key: string, entry: PrMemoryEntry): void {
  mkdirSync(getMemoryDir(), { recursive: true });
  const entries = loadPrMemory(key);
  entries.push(entry);
  writeFileSync(getMemoryPath(key), JSON.stringify(entries, null, 2));
}

export function clearPrMemory(key: string): void {
  const filePath = getMemoryPath(key);
  if (existsSync(filePath)) {
    rmSync(filePath, { force: true });
  }
}

export function clearClosedPrMemories(repoName: string, openPrNumbers: readonly number[]): number {
  const dir = getMemoryDir();
  if (!existsSync(dir)) return 0;

  const openSet = new Set(openPrNumbers);
  const prefix = `${repoName}#`;
  let cleared = 0;

  for (const file of readdirSync(dir)) {
    if (!file.startsWith(prefix) || !file.endsWith(".json")) continue;

    const prNumber = Number(file.slice(prefix.length, -".json".length));
    if (!Number.isFinite(prNumber) || openSet.has(prNumber)) continue;

    rmSync(join(dir, file), { force: true });
    cleared++;
  }

  return cleared;
}

function getMemoryDir(): string {
  return resolve(process.cwd(), MEMORY.DIR);
}

function getMemoryPath(key: string): string {
  return join(getMemoryDir(), `${key}.json`);
}

function isPrMemoryEntry(value: unknown): value is PrMemoryEntry {
  if (!value || typeof value !== "object") return false;

  const candidate = value as Record<string, unknown>;
  return (
    typeof candidate.commentId === "number" &&
    typeof candidate.commentAuthor === "string" &&
    typeof candidate.commentBody === "string" &&
    typeof candidate.agentReply === "string" &&
    Array.isArray(candidate.filesChanged) &&
    candidate.filesChanged.every((file) => typeof file === "string") &&
    typeof candidate.timestamp === "string"
  );
}
