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

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

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;
}

function discoverFrameworkSkills(): string[] {
  if (!fs.existsSync(SKILLS_SRC)) return [];
  return fs
    .readdirSync(SKILLS_SRC, { withFileTypes: true })
    .filter((entry) => entry.isDirectory() && entry.name.startsWith("erp-kit-"))
    .map((entry) => entry.name);
}

export function copySkills(cwd: string): CopyResult {
  const skillsDest = path.join(cwd, ".agents", "skills");

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

  let copied = 0;
  for (const skill of discoverFrameworkSkills()) {
    const srcSkillDir = path.join(SKILLS_SRC, skill);
    if (!fs.existsSync(srcSkillDir)) continue;
    const destDir = path.join(skillsDest, skill);
    copied += copyDirectoryRecursive(srcSkillDir, destDir);
  }

  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"));

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

  return { copied, removed: 0 };
}

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);
}

function copySkillsDirectory(src: string, dest: string): void {
  if (!fs.existsSync(src)) return;
  fs.cpSync(src, dest, { recursive: true });
}

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 {
        copySkillsDirectory(skillsDest, claudeSkills);
        return "copied";
      }
    }
    return "skipped_directory";
  }

  fs.mkdirSync(path.dirname(claudeSkills), { recursive: true });
  try {
    createSymlink(relTarget, claudeSkills);
    return "linked";
  } catch {
    copySkillsDirectory(skillsDest, 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;
  }
  // It's a real directory — delete and re-copy from .agents/skills
  const skillsDest = path.join(cwd, ".agents", "skills");
  fs.rmSync(claudeSkills, { recursive: true, force: true });
  copySkillsDirectory(skillsDest, 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-"));
}
