/**
 * Shared plugin utilities for OpenCode plugins.
 */
import { execSync } from "child_process";
import * as fs from "fs";
import * as path from "path";

export interface GitInfo {
  is_repo: boolean;
  branch: string;
  changes_count: number;
  has_changes: boolean;
  changes: string[];
}

export function getGitInfo(cwd: string): GitInfo {
  try {
    execSync("git rev-parse --git-dir", { cwd, stdio: "pipe" });
    let branch = "unknown";
    try {
      branch = execSync("git branch --show-current", { cwd, encoding: "utf8", stdio: "pipe" }).trim();
    } catch {}
    let changes = "";
    try {
      changes = execSync("git status --porcelain", { cwd, encoding: "utf8", stdio: "pipe" });
    } catch {}
    const changeList = changes.trim().split("\n").filter(Boolean);
    return { is_repo: true, branch, changes_count: changeList.length, has_changes: changeList.length > 0, changes: changeList };
  } catch {
    return { is_repo: false, branch: "unknown", changes_count: 0, has_changes: false, changes: [] };
  }
}

export interface TodoInfo {
  found: boolean;
  file: string | null;
  path: string | null;
  total: number;
  done: number;
  pending: number;
}

export function getTodoInfo(cwd: string): TodoInfo {
  const todoFiles = [
    path.join(cwd, "docs", "todo.md"),
    path.join(cwd, "TODO.md"),
    path.join(cwd, ".opencode", "todos.md"),
    path.join(cwd, "TODO"),
    path.join(cwd, "notes", "todo.md"),
  ];
  for (const file of todoFiles) {
    if (fs.existsSync(file)) {
      try {
        const content = fs.readFileSync(file, "utf8");
        const total = (content.match(/^[-*] \[[ x]\]/gim) || []).length;
        const done = (content.match(/^[-*] \[x\]/gim) || []).length;
        return { found: true, file: path.basename(file), path: file, total, done, pending: total - done };
      } catch { continue; }
    }
  }
  return { found: false, file: null, path: null, total: 0, done: 0, pending: 0 };
}


export interface ProjectMemoryBinding {
  bound: boolean;
  registryPath: string | null;
  memoryPath: string | null;
  projectId: string | null;
  vaultRoot: string | null;
}

export interface ResearchRepoCandidate {
  candidate: boolean;
  markers: string[];
}

export function getProjectMemoryBinding(cwd: string): ProjectMemoryBinding {
  const registryPath = path.join(cwd, ".opencode", "project-memory", "registry.yaml");
  if (!fs.existsSync(registryPath)) {
    return { bound: false, registryPath: null, memoryPath: null, projectId: null, vaultRoot: null };
  }
  try {
    const raw = fs.readFileSync(registryPath, "utf8").trim();
    const data = raw ? JSON.parse(raw) : {};
    const projects = data.projects || {};
    const firstKey = Object.keys(projects)[0];
    if (!firstKey) {
      return { bound: false, registryPath, memoryPath: null, projectId: null, vaultRoot: null };
    }
    const project = projects[firstKey] || {};
    const memoryPath = path.join(cwd, ".opencode", "project-memory", `${firstKey}.md`);
    return {
      bound: true,
      registryPath,
      memoryPath,
      projectId: firstKey,
      vaultRoot: project.vault_root || project.project_root || project.vault_path || null,
    };
  } catch {
    return { bound: false, registryPath, memoryPath: null, projectId: null, vaultRoot: null };
  }
}

export function detectResearchRepoCandidate(cwd: string): ResearchRepoCandidate {
  const markers: string[] = [];
  const checks = [
    ".git",
    "README.md",
    path.join("docs"),
    path.join("notes"),
    path.join("plan"),
    path.join("results"),
    path.join("outputs"),
    path.join("src"),
    path.join("scripts"),
  ];
  for (const rel of checks) {
    if (fs.existsSync(path.join(cwd, rel))) markers.push(rel);
  }
  return { candidate: markers.length >= 3, markers };
}