import { FormatterRegistry } from '@promptscript/formatters';
import { detectFormat, type DetectedFormat } from '@promptscript/importer';
import { type CliServices, createDefaultServices } from '../services.js';

/**
 * AI tool target identifier — corresponds to a registered formatter name.
 */
export type AIToolTarget = string;

/**
 * Enriched migration candidate with metadata about the instruction file.
 */
export interface MigrationCandidate {
  path: string;
  format: DetectedFormat;
  sizeBytes: number;
  sizeHuman: string;
  toolName: string;
}

/**
 * AI tool detection result.
 */
export interface AIToolsDetection {
  /** Detected AI tools with existing configuration */
  detected: AIToolTarget[];
  /** Details about detected files */
  details: Record<string, string[]>;
  /** Files that exist but were NOT generated by PromptScript (candidates for migration) */
  migrationCandidates: MigrationCandidate[];
}

/**
 * File patterns for each AI tool.
 */
interface AIToolPattern {
  target: AIToolTarget;
  files: string[];
  directories: string[];
}

/**
 * Marker comment that indicates a file was generated by PromptScript.
 */
const PROMPTSCRIPT_MARKER = 'PromptScript';

/**
 * Files that are instruction files (not just config) and can be migrated.
 */
const INSTRUCTION_FILES = [
  'CLAUDE.md',
  'claude.md',
  '.cursorrules',
  '.github/copilot-instructions.md',
  'AGENTS.md',
  'AI_INSTRUCTIONS.md',
  'AI.md',
  'OPENCODE.md',
  'GEMINI.md',
  '.windsurfrules',
  '.clinerules',
  '.goosehints',
  'augment-guidelines.md',
  'codex.md',
];

function formatFileSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  return `${(bytes / 1024).toFixed(1)} KB`;
}

const FILE_TOOL_NAMES: Record<string, string> = {
  'CLAUDE.md': 'Claude Code',
  'claude.md': 'Claude Code',
  '.cursorrules': 'Cursor',
  '.github/copilot-instructions.md': 'GitHub Copilot',
  'AGENTS.md': 'Factory AI / Codex',
  'OPENCODE.md': 'OpenCode',
  'GEMINI.md': 'Gemini CLI',
  '.windsurfrules': 'Windsurf',
  '.clinerules': 'Cline',
  '.goosehints': 'Goose',
  'augment-guidelines.md': 'Augment',
  'codex.md': 'Codex',
  'AI_INSTRUCTIONS.md': 'Generic',
  'AI.md': 'Generic',
};

function toolNameForFile(file: string): string {
  return FILE_TOOL_NAMES[file] ?? 'Unknown';
}

/**
 * Known detection patterns for AI tools.
 * Used to detect existing configurations on disk.
 * Formatters without explicit patterns here can still be selected as targets.
 */
const AI_TOOL_PATTERNS: AIToolPattern[] = [
  {
    target: 'github',
    files: ['.github/copilot-instructions.md'],
    directories: ['.github'],
  },
  {
    target: 'claude',
    files: ['CLAUDE.md', '.claude/settings.json', 'claude.md'],
    directories: ['.claude'],
  },
  {
    target: 'cursor',
    files: ['.cursor/rules/project.mdc', '.cursorrules', '.cursor/rules.md'],
    directories: ['.cursor', '.cursor/rules'],
  },
  {
    target: 'antigravity',
    files: ['.agent/rules/project.md'],
    directories: ['.agent', '.agent/rules'],
  },
  {
    target: 'factory',
    files: ['AGENTS.md', '.factory/config.json'],
    directories: ['.factory', '.factory/skills'],
  },
  {
    target: 'opencode',
    files: ['OPENCODE.md'],
    directories: ['.opencode', '.opencode/commands', '.opencode/skills', '.opencode/agents'],
  },
  {
    target: 'gemini',
    files: ['GEMINI.md', '.gemini/settings.json'],
    directories: ['.gemini', '.gemini/commands', '.gemini/skills'],
  },
  {
    target: 'windsurf',
    files: ['.windsurfrules'],
    directories: ['.windsurf'],
  },
  {
    target: 'cline',
    files: ['.clinerules'],
    directories: ['.cline'],
  },
  {
    target: 'roo',
    files: ['.roo/rules/project.md'],
    directories: ['.roo', '.roo/rules'],
  },
  {
    target: 'codex',
    files: ['AGENTS.md', 'codex.md'],
    directories: [],
  },
  {
    target: 'continue',
    files: ['.continue/config.json', '.continue/rules/project.md'],
    directories: ['.continue'],
  },
  {
    target: 'augment',
    files: ['augment-guidelines.md', '.augment/config.json'],
    directories: ['.augment'],
  },
  {
    target: 'goose',
    files: ['.goosehints'],
    directories: [],
  },
  {
    target: 'kilo',
    files: ['.kilo/rules/project.md'],
    directories: ['.kilo'],
  },
  {
    target: 'amp',
    files: ['AGENTS.md'],
    directories: ['.ampt'],
  },
  {
    target: 'trae',
    files: ['.trae/rules/project.md'],
    directories: ['.trae'],
  },
  {
    target: 'junie',
    files: ['.junie/guidelines.md'],
    directories: ['.junie'],
  },
  {
    target: 'kiro',
    files: ['.kiro/rules/project.md'],
    directories: ['.kiro'],
  },
];

/**
 * Check if a directory exists and is not empty.
 */
async function directoryHasContent(dir: string, services: CliServices): Promise<boolean> {
  if (!services.fs.existsSync(dir)) return false;
  try {
    const entries = await services.fs.readdir(dir);
    return entries.length > 0;
  } catch {
    return false;
  }
}

/**
 * Check if a file was generated by PromptScript.
 * PromptScript-generated files contain a marker comment near the top.
 */
async function isPromptScriptGenerated(filePath: string, services: CliServices): Promise<boolean> {
  try {
    const content = await services.fs.readFile(filePath, 'utf-8');
    // Check first 500 characters for the marker (it's usually in the first few lines)
    const header = content.slice(0, 500);
    return header.includes(PROMPTSCRIPT_MARKER);
  } catch {
    return false;
  }
}

/**
 * Detect existing AI tool configurations.
 */
export async function detectAITools(
  services: CliServices = createDefaultServices()
): Promise<AIToolsDetection> {
  const detected: AIToolTarget[] = [];
  const details: Record<string, string[]> = {};
  const migrationCandidates: MigrationCandidate[] = [];

  for (const pattern of AI_TOOL_PATTERNS) {
    const foundFiles: string[] = [];

    // Check specific files
    for (const file of pattern.files) {
      if (services.fs.existsSync(file)) {
        foundFiles.push(file);
      }
    }

    // Check directories
    for (const dir of pattern.directories) {
      if (await directoryHasContent(dir, services)) {
        foundFiles.push(`${dir}/`);
      }
    }

    if (foundFiles.length > 0) {
      detected.push(pattern.target);
      details[pattern.target] = foundFiles;
    }
  }

  // Check for instruction files that are NOT PromptScript-generated
  for (const file of INSTRUCTION_FILES) {
    if (services.fs.existsSync(file)) {
      const isGenerated = await isPromptScriptGenerated(file, services);
      if (!isGenerated) {
        let sizeBytes = 0;
        try {
          const content = await services.fs.readFile(file, 'utf-8');
          sizeBytes = Buffer.byteLength(content ?? '', 'utf-8');
        } catch {
          // Size unknown — use 0
        }
        migrationCandidates.push({
          path: file,
          format: detectFormat(file),
          sizeBytes,
          sizeHuman: formatFileSize(sizeBytes),
          toolName: toolNameForFile(file),
        });
      }
    }
  }

  return { detected, details, migrationCandidates };
}

/**
 * Get all available targets from the FormatterRegistry.
 */
export function getAllTargets(): AIToolTarget[] {
  return FormatterRegistry.list();
}

/**
 * Get suggested targets based on detection.
 * If no tools detected, suggest common defaults. Otherwise, suggest detected ones.
 */
export function getSuggestedTargets(detection: AIToolsDetection): AIToolTarget[] {
  if (detection.detected.length > 0) {
    return detection.detected;
  }
  // Default suggestions for new projects (most common tools)
  const defaults = ['github', 'claude', 'cursor'];
  const available = new Set(getAllTargets());
  return defaults.filter((t) => available.has(t));
}

/**
 * Format detection results for display.
 */
export function formatDetectionResults(detection: AIToolsDetection): string[] {
  const lines: string[] = [];

  if (detection.detected.length === 0) {
    lines.push('No existing AI tool configurations detected.');
    return lines;
  }

  lines.push('Detected AI tool configurations:');

  for (const target of detection.detected) {
    const files = detection.details[target];
    if (files) {
      lines.push(`  • ${target}: ${files.join(', ')}`);
    }
  }

  return lines;
}

/**
 * Check if there are migration candidates (non-PromptScript instruction files).
 */
export function hasMigrationCandidates(detection: AIToolsDetection): boolean {
  return detection.migrationCandidates.length > 0;
}

/**
 * Format migration hint for display.
 */
export function formatMigrationHint(detection: AIToolsDetection): string[] {
  if (detection.migrationCandidates.length === 0) {
    return [];
  }

  const lines: string[] = [];
  lines.push('');
  lines.push('Existing instruction files detected:');
  for (const c of detection.migrationCandidates) {
    lines.push(`   - ${c.path} (${c.sizeHuman}, ${c.toolName})`);
  }
  lines.push('');
  lines.push('   These can be migrated to PromptScript for unified management.');
  lines.push('   Run: prs migrate');
  lines.push('   See: https://getpromptscript.dev/latest/guides/ai-migration-best-practices');

  return lines;
}
