import fs from "node:fs";
import path from "node:path";
import { PACKAGE_ROOT } from "../../util";

export const SKILLS_SRC = path.join(PACKAGE_ROOT, "skills");
const WORKFLOWS_SRC = path.join(PACKAGE_ROOT, "templates", "workflows");
const ACTIONS_SRC = path.join(PACKAGE_ROOT, "templates", "actions");

export interface CopyResult {
  copied: number;
  removed: number;
}

function copyDirectoryRecursive(srcDir: string, destDir: string): number {
  let copied = 0;
  for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
    const srcPath = path.join(srcDir, entry.name);
    const destPath = path.join(destDir, entry.name);
    if (entry.isDirectory()) {
      copied += copyDirectoryRecursive(srcPath, destPath);
    } else {
      fs.mkdirSync(destDir, { recursive: true });
      fs.copyFileSync(srcPath, destPath);
      copied++;
    }
  }
  return copied;
}

// Replace erp-kit-* skills in destDir with the current ones, leaving custom skills untouched.
export function copySkills(destDir: string): CopyResult {
  let removed = 0;
  if (fs.existsSync(destDir)) {
    for (const entry of fs.readdirSync(destDir)) {
      if (entry.startsWith("erp-kit-")) {
        fs.rmSync(path.join(destDir, entry), { recursive: true, force: true });
        removed++;
      }
    }
  }

  let copied = 0;
  for (const entry of fs.readdirSync(SKILLS_SRC)) {
    fs.cpSync(path.join(SKILLS_SRC, entry), path.join(destDir, entry), { recursive: true });
    copied++;
  }

  return { copied, removed };
}

export function copyWorkflows(cwd: string): CopyResult {
  const workflowsDest = path.join(cwd, ".github", "workflows");
  if (!fs.existsSync(WORKFLOWS_SRC)) return { copied: 0, removed: 0 };

  const workflowFiles = fs
    .readdirSync(WORKFLOWS_SRC)
    .filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));

  const sourceNames = new Set(workflowFiles);

  let removed = 0;
  if (fs.existsSync(workflowsDest)) {
    for (const entry of fs.readdirSync(workflowsDest)) {
      if (entry.startsWith("erp-kit-") && !sourceNames.has(entry)) {
        fs.rmSync(path.join(workflowsDest, entry), { force: true });
        removed++;
      }
    }
  }

  if (workflowFiles.length === 0) return { copied: 0, removed };
  fs.mkdirSync(workflowsDest, { recursive: true });

  let copied = 0;
  for (const file of workflowFiles) {
    fs.copyFileSync(path.join(WORKFLOWS_SRC, file), path.join(workflowsDest, file));
    copied++;
  }

  return { copied, removed };
}

export function copyActions(cwd: string): CopyResult {
  const actionsDest = path.join(cwd, ".github", "actions");
  if (!fs.existsSync(ACTIONS_SRC)) return { copied: 0, removed: 0 };

  const actionDirs = fs
    .readdirSync(ACTIONS_SRC, { withFileTypes: true })
    .filter((entry) => entry.isDirectory() && entry.name.startsWith("erp-kit-"));

  const sourceNames = new Set(actionDirs.map((d) => d.name));

  let removed = 0;
  if (fs.existsSync(actionsDest)) {
    for (const entry of fs.readdirSync(actionsDest)) {
      if (entry.startsWith("erp-kit-") && !sourceNames.has(entry)) {
        fs.rmSync(path.join(actionsDest, entry), { recursive: true, force: true });
        removed++;
      }
    }
  }

  let copied = 0;
  for (const dir of actionDirs) {
    const srcDir = path.join(ACTIONS_SRC, dir.name);
    const destDir = path.join(actionsDest, dir.name);
    copied += copyDirectoryRecursive(srcDir, destDir);
  }

  return { copied, removed };
}

export type SymlinkResult = "linked" | "already_linked" | "skipped_directory" | "copied";

function createSymlink(target: string, linkPath: string): void {
  const type = process.platform === "win32" ? "junction" : undefined;
  // Junctions on Windows require absolute targets
  const resolvedTarget =
    type === "junction" ? path.resolve(path.dirname(linkPath), target) : target;
  fs.symlinkSync(resolvedTarget, linkPath, type);
}

export function setupSymlink(cwd: string): SymlinkResult {
  const skillsDest = path.join(cwd, ".agents", "skills");
  const claudeSkills = path.join(cwd, ".claude", "skills");
  const relTarget = path.relative(path.dirname(claudeSkills), skillsDest);

  let exists = false;
  try {
    fs.lstatSync(claudeSkills);
    exists = true;
  } catch {
    // doesn't exist
  }

  if (exists) {
    const stat = fs.lstatSync(claudeSkills);
    if (stat.isSymbolicLink()) {
      const current = fs.readlinkSync(claudeSkills);
      if (current === relTarget) return "already_linked";
      fs.unlinkSync(claudeSkills);
      try {
        createSymlink(relTarget, claudeSkills);
        return "linked";
      } catch {
        copySkills(claudeSkills);
        return "copied";
      }
    }
    return "skipped_directory";
  }

  fs.mkdirSync(path.dirname(claudeSkills), { recursive: true });
  try {
    createSymlink(relTarget, claudeSkills);
    return "linked";
  } catch {
    copySkills(claudeSkills);
    return "copied";
  }
}

/**
 * When .claude/skills is a real directory (copy fallback on Windows),
 * re-sync it with .agents/skills after an update.
 */
export function refreshCopiedSkills(cwd: string): boolean {
  const claudeSkills = path.join(cwd, ".claude", "skills");
  try {
    const stat = fs.lstatSync(claudeSkills);
    if (stat.isSymbolicLink() || !stat.isDirectory()) return false;
  } catch {
    return false;
  }
  copySkills(claudeSkills);
  return true;
}

export function isAlreadyInitialized(cwd: string): boolean {
  const skillsDest = path.join(cwd, ".agents", "skills");
  if (!fs.existsSync(skillsDest)) return false;
  return fs.readdirSync(skillsDest).some((entry) => entry.startsWith("erp-kit-"));
}
