/** Direct markdown parsing of backlog task files for AC read/toggle. */

import { readdir } from "node:fs/promises";
import { repoPath } from "./checklist-config";

const AC_BEGIN = "<!-- AC:BEGIN -->";
const AC_END = "<!-- AC:END -->";
const AC_REGEX = /^- \[([ x])\] #(\d+) (.+)$/;

export interface AcceptanceCriterion {
  index: number;
  checked: boolean;
  text: string;
}

export interface TaskInfo {
  title: string;
  status: string;
  criteria: AcceptanceCriterion[];
  filePath: string;
}

/**
 * Find the task markdown file in the backlog directory.
 * Files are named like "task-high.3 - Some-title.md" where the taskId
 * is the prefix before " - ". Case-insensitive match.
 */
async function findTaskFile(repo: string, taskId: string): Promise<string> {
  const base = repoPath(repo);
  const tasksDir = `${base}/backlog/tasks`;

  const exact = `${tasksDir}/${taskId}.md`;
  if (await Bun.file(exact).exists()) return exact;

  const files = await readdir(tasksDir);
  const lower = taskId.toLowerCase();
  const match = files.find((f) => f.toLowerCase().startsWith(lower + " - ") && f.endsWith(".md"));
  if (match) return `${tasksDir}/${match}`;

  throw new Error(`Task file not found for ${taskId} in ${tasksDir}`);
}

function parseTitle(content: string): string {
  const fmMatch = content.match(/^---\n[\s\S]*?title:\s*["']?(.+?)["']?\s*\n[\s\S]*?---/);
  if (fmMatch?.[1]) return fmMatch[1];
  const headingMatch = content.match(/^#\s+(.+)$/m);
  return headingMatch?.[1] || "Untitled Task";
}

function parseStatus(content: string): string {
  const match = content.match(/^status:\s*["']?(.+?)["']?\s*$/m);
  return match?.[1] || "Unknown";
}

function parseAC(content: string): AcceptanceCriterion[] {
  const normalized = content.replace(/\r\n/g, "\n");
  const beginIdx = normalized.indexOf(AC_BEGIN);
  const endIdx = normalized.indexOf(AC_END);
  if (beginIdx === -1 || endIdx === -1) return [];

  const acContent = normalized.substring(beginIdx + AC_BEGIN.length, endIdx);
  const lines = acContent.split("\n").filter((l) => l.trim());
  const criteria: AcceptanceCriterion[] = [];

  for (const line of lines) {
    const match = line.match(AC_REGEX);
    if (match?.[1] && match?.[2] && match?.[3]) {
      criteria.push({
        checked: match[1] === "x",
        text: match[3],
        index: parseInt(match[2], 10),
      });
    }
  }
  return criteria;
}

export async function readTask(repo: string, taskId: string): Promise<TaskInfo> {
  const filePath = await findTaskFile(repo, taskId);
  const content = await Bun.file(filePath).text();
  return {
    title: parseTitle(content),
    status: parseStatus(content),
    criteria: parseAC(content),
    filePath,
  };
}

/**
 * Toggle an AC item: unchecked → checked, checked → unchecked.
 * Returns the new checked state.
 */
export async function toggleAC(repo: string, taskId: string, acIndex: number): Promise<TaskInfo & { toggled: boolean }> {
  const filePath = await findTaskFile(repo, taskId);
  let content = await Bun.file(filePath).text();

  const unchecked = `- [ ] #${acIndex} `;
  const checked = `- [x] #${acIndex} `;
  let nowChecked = false;
  if (content.includes(unchecked)) {
    content = content.replace(unchecked, checked);
    nowChecked = true;
    await Bun.write(filePath, content);
  } else if (content.includes(checked)) {
    content = content.replace(checked, unchecked);
    nowChecked = false;
    await Bun.write(filePath, content);
  }

  return {
    title: parseTitle(content),
    status: parseStatus(content),
    criteria: parseAC(content),
    filePath,
    toggled: nowChecked,
  };
}
