'use client';

import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import {
  FileCode2, GitBranch, Database, Network, AlertTriangle, CheckCircle2,
  Activity, Layers, Zap, Clock, ChevronDown, ChevronUp,
  Search, Filter, Download, Eye, X, Play, Loader2, Code, Shield,
  ArrowRight, ArrowLeft, Plus, Trash2, Lock, LockOpen, RotateCcw
} from 'lucide-react';
import type { Project } from '../data/projectsData';
import { api } from '../lib/api';
import { proposeDependencyMappings, type DependencyEntry } from '../lib/dependency-proposals';
import type { DepKind } from '../lib/analyze-source';

const KIND_LABEL: Record<string, string> = {
  copybook: 'Copybook', 'called-program': 'Program', 'cics-program': 'CICS',
  'cics-map': 'BMS map', 'sql-table': 'DB2 table', dataset: 'Dataset', 'external-lib': 'Library',
};
type DepItem = { name: string; kind: DepKind };
/** Normalise the dependency list (tolerates legacy cached entries stored as plain strings). */
function depItems(list: Array<DepItem | string> | undefined): DepItem[] {
  return (list ?? []).map((d) => (typeof d === 'string' ? { name: d, kind: 'external-lib' as DepKind } : d));
}
/** Public registry that hosts packages for the target language (for verify validation). */
function ecosystemFor(lang: string): 'npm' | 'maven' | null {
  const t = (lang ?? '').toLowerCase();
  if (['javascript', 'typescript', 'node'].includes(t)) return 'npm';
  if (['java', 'kotlin', 'scala', 'groovy'].includes(t)) return 'maven';
  return null;
}

interface Props {
  initialView?: 'results' | 'dep-mapping';
  projectId: string;
  onNavigate?: (section: string, projectId?: string) => void;
  maxReachedStep?: number;
  project?: Project | null;
}

interface AnalysisData {
  scanResults: {
    totalFiles: number;
    totalSourceFiles: number;
    totalDirectories: number;
    totalSize: number;
    totalLines: number;
    totalCodeLines: number;
    totalCommentLines: number;
    totalBlankLines: number;
    languages: { name: string; bytes: number; files: number; percentage: number }[];
    extensions: { ext: string; count: number; percentage: number }[];
  };
  complexity: {
    avgCyclomatic: number;
    maxCyclomatic: number;
    avgNesting: number;
    maxNesting: number;
    totalProcedures: number;
    totalSections: number;
    avgLines: number;
    maxLines: number;
  };
  dependencies: {
    total: number;
    shown?: number;
    truncated?: boolean;
    byKind?: { copybook: number; calledProgram: number; cicsProgram: number; cicsMap: number; sqlTable: number; dataset: number; externalLib: number };
    copybooks: number;
    externalCalls: number;
    manifestPackages: number;
    circularDeps: number;
    orphanFiles: number;
    selfContainedFiles?: number;
    list: Array<{ name: string; kind: DepKind } | string>;
    graph?: { edges: Array<{ from: string; to: string; kind: DepKind }>; copybookFanIn: Array<{ name: string; count: number }> };
  };
  risk: {
    high: number;
    medium: number;
    low: number;
    files: {
      name: string; path: string; lines: number; codeLines: number;
      complexity: number; nesting: number; risk: 'high' | 'medium' | 'low';
      dependencies: number; procedures: number; size: number;
    }[];
  };
  analyzedFileCount: number;
}

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

const langColors: Record<string, string> = {
  COBOL: '#005ca5', Java: '#b07219', Python: '#3572A5', JavaScript: '#f1e05a',
  TypeScript: '#3178c6', 'C#': '#178600', JCL: '#8a8a8a', Shell: '#89e051',
  SQL: '#e38c00', PLI: '#3d6117', REXX: '#d90e09',
};

const riskColor = (risk: string) => {
  switch (risk) {
    case 'high': return 'text-red-400 bg-red-500/15';
    case 'medium': return 'text-amber-400 bg-amber-500/15';
    case 'low': return 'text-green-400 bg-green-500/15';
    default: return 'text-muted bg-surface-light';
  }
};

// Animated analysis steps shown during loading
const analysisStepsRepo = [
  { label: 'Cloning repository tree...', icon: GitBranch },
  { label: 'Scanning file structure...', icon: FileCode2 },
  { label: 'Analyzing language distribution...', icon: Code },
  { label: 'Computing cyclomatic complexity...', icon: Layers },
  { label: 'Mapping dependencies...', icon: Network },
  { label: 'Assessing risk levels...', icon: Shield },
  { label: 'Generating report...', icon: Activity },
];
const analysisStepsUpload = [
  { label: 'Reading uploaded file list...', icon: FileCode2 },
  { label: 'Filtering source files...', icon: Search },
  { label: 'Estimating code metrics...', icon: Layers },
  { label: 'Mapping dependencies...', icon: Network },
  { label: 'Assessing risk levels...', icon: Shield },
  { label: 'Generating report...', icon: Activity },
];

export default function PreAnalysisDashboard({ projectId, onNavigate, maxReachedStep = 0, project: propProject, initialView }: Props) {
  const [selectedFile, setSelectedFile] = useState<string | null>(null);
  const [analysis, setAnalysis] = useState<AnalysisData | null>(null);
  const [analyzing, setAnalyzing] = useState(false);
  const [analyzeError, setAnalyzeError] = useState<string | null>(null);
  const [currentStep, setCurrentStep] = useState(0);
  const [view] = useState<'results' | 'dep-mapping'>(initialView ?? 'results');
  const [depMapping, setDepMapping] = useState<DependencyEntry[]>([]);
  const [savingMapping, setSavingMapping] = useState(false);
  const [proposingDeps, setProposingDeps] = useState(false);
  const [mappingLocked, setMappingLocked] = useState(false);

  const project = propProject;
  const isDraft = !project || (project.status === 'draft' && maxReachedStep < 1);
  const repoUrl = project?.repoUrl || ((project?.config as any)?.repoUrl) || '';
  const branch = ((project?.config as any)?.branch) || 'main';
  const sourceLanguage = (project?.sourceLanguage ?? '').trim();
  const additionalSourceLanguages: string[] = (project?.config as any)?.additionalSourceLanguages ?? [];
  const selectedProvider: string = (project?.config as any)?.selectedProvider || 'GitHub';
  const uploadId: string = (project?.config as any)?.uploadId || '';
  const folderName: string = (project?.config as any)?.folderName || '';
  const isLocalFolder = !repoUrl && !!uploadId;

  // Hydrate analysis state from project config (for completed projects)
  useEffect(() => {
    const saved = (project?.config as any)?.preAnalysis;
    if (saved && !analysis && !analyzing) setAnalysis(saved);
  }, [project]);

  // Hydrate saved dependency mapping and lock state
  useEffect(() => {
    const saved = (project?.config as any)?.dependencyMapping;
    if (Array.isArray(saved) && saved.length > 0) setDepMapping(saved);
    const locked = (project?.config as any)?.dependencyMappingLocked === true;
    if (locked) setMappingLocked(true);
  }, [project]);

  // Auto-fetch proposals when landing on dep-mapping view with no existing mapping
  useEffect(() => {
    if (view !== 'dep-mapping' || depMapping.length > 0 || !analysis || proposingDeps) return;
    const depList = analysis.dependencies.list;
    if (depList.length === 0) return;
    setProposingDeps(true);
    fetchProposals()
      .then(({ entries, tokens }) => {
        setDepMapping(entries);
        if (tokens > 0) {
          api.recordStepProgress(projectId, 2, 'completed', maxReachedStep, { actualTokens: tokens }).catch(() => {});
        }
      })
      .finally(() => setProposingDeps(false));
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [view, analysis]);

  const analysisSteps = isLocalFolder ? analysisStepsUpload : analysisStepsRepo;

  // Animate analysis steps during loading
  useEffect(() => {
    if (!analyzing) return;
    const interval = setInterval(() => {
      setCurrentStep(prev => (prev < analysisSteps.length - 1 ? prev + 1 : prev));
    }, 1800);
    return () => clearInterval(interval);
  }, [analyzing]);

  const startAnalysis = async () => {
    if (!sourceLanguage) {
      setAnalyzeError('This project has no source language set. Update the project before running analysis.');
      return;
    }
    setAnalyzing(true);
    setAnalyzeError(null);
    setCurrentStep(0);
    try {
      let data: any;

      if (isLocalFolder) {
        const res = await fetch(`/api/conversions/${projectId}/analyze-upload`, { method: 'POST' });
        data = await res.json();
      } else {
        const extraParam = additionalSourceLanguages.length > 0
          ? `&additionalSourceLanguages=${encodeURIComponent(additionalSourceLanguages.join(','))}`
          : '';
        const analyzeEndpoint =
          selectedProvider === 'GitLab' ? '/api/gitlab/analyze'
          : selectedProvider === 'Bitbucket' ? '/api/bitbucket/analyze'
          : selectedProvider === 'Azure DevOps' ? '/api/azure/analyze'
          : '/api/github/analyze';
        const res = await fetch(
          `${analyzeEndpoint}?repoUrl=${encodeURIComponent(repoUrl)}&branch=${encodeURIComponent(branch)}&sourceLanguage=${encodeURIComponent(sourceLanguage)}${extraParam}`
        );
        data = await res.json();
      }

      if (data.error) {
        setAnalyzeError(data.error);
      } else {
        setAnalysis(data);
        // Persist analysis to project config so it survives navigation (local folder route already persists server-side)
        if (!isLocalFolder) {
          try {
            await api.updateProject(projectId, {
              config: { preAnalysis: data },
              totalFiles: data.scanResults?.totalSourceFiles ?? 0,
              totalLines: data.scanResults?.totalLines ?? 0,
            });
          } catch {
            // Non-critical — results already displayed in state
          }
        }
      }
    } catch {
      setAnalyzeError('Failed to run analysis');
    } finally {
      setAnalyzing(false);
    }
  };

  // ─── Draft state ───
  if (isDraft) {
    return (
      <div className="space-y-6">
        <motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }}>
          <h2 className="text-2xl font-bold text-foreground">Pre-Migration Analysis</h2>
          <p className="text-sm text-muted mt-1">Comprehensive analysis of source code before migration</p>
        </motion.div>
        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="glass-light rounded-lg p-12 text-center">
          <div className="w-20 h-20 rounded-full gradient-accent flex items-center justify-center mx-auto mb-6">
            <Play className="w-10 h-10 text-white" />
          </div>
          <h3 className="text-xl font-semibold text-foreground mb-3">Analysis Not Started</h3>
          <p className="text-sm text-muted mb-8 max-w-md mx-auto">
            Connect a repository first to run pre-migration analysis.
          </p>
          <button onClick={() => onNavigate?.('repository', projectId)} className="px-8 py-3 rounded-lg gradient-accent text-white text-sm font-semibold hover:opacity-90 transition-opacity flex items-center justify-center gap-2 cursor-pointer mx-auto glow-accent">
            <Play className="w-5 h-5" /> Connect Repository
          </button>
        </motion.div>
      </div>
    );
  }

  // ─── Analyzing state ───
  if (analyzing) {
    return (
      <div className="space-y-6">
        <motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }}>
          <h2 className="text-2xl font-bold text-foreground">Pre-Migration Analysis</h2>
          <p className="text-sm text-muted mt-1">Analyzing {isLocalFolder ? folderName || 'uploaded folder' : repoUrl.replace(/^https?:\/\//, '')}...</p>
        </motion.div>
        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-8">
          <div className="max-w-lg mx-auto space-y-4">
            {analysisSteps.map((step, i) => {
              const Icon = step.icon;
              const done = i < currentStep;
              const active = i === currentStep;
              return (
                <motion.div
                  key={step.label}
                  initial={{ opacity: 0, x: -10 }}
                  animate={{ opacity: i <= currentStep ? 1 : 0.3, x: 0 }}
                  transition={{ delay: i * 0.15 }}
                  className={`flex items-center gap-3 p-3 rounded-lg transition-all ${active ? 'glass-light border border-accent/30' : ''}`}
                >
                  {done ? (
                    <CheckCircle2 className="w-5 h-5 text-success flex-shrink-0" />
                  ) : active ? (
                    <Loader2 className="w-5 h-5 text-accent-light animate-spin flex-shrink-0" />
                  ) : (
                    <Icon className="w-5 h-5 text-muted/40 flex-shrink-0" />
                  )}
                  <span className={`text-sm ${active ? 'text-foreground font-medium' : done ? 'text-muted' : 'text-muted/40'}`}>
                    {step.label}
                  </span>
                  {done && <span className="text-[10px] text-success ml-auto">Done</span>}
                </motion.div>
              );
            })}
          </div>
          <div className="mt-6">
            <div className="h-1.5 bg-surface-light rounded-full overflow-hidden">
              <motion.div
                className="h-full rounded-full bg-accent"
                initial={{ width: 0 }}
                animate={{ width: `${((currentStep + 1) / analysisSteps.length) * 100}%` }}
                transition={{ duration: 0.5 }}
              />
            </div>
          </div>
        </motion.div>
      </div>
    );
  }

  // ─── Ready to analyze (no results yet) ───
  if (!analysis) {
    return (
      <div className="space-y-6">
        <motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }}>
          <h2 className="text-2xl font-bold text-foreground">Pre-Migration Analysis</h2>
          <p className="text-sm text-muted mt-1">Comprehensive analysis of source code before migration</p>
        </motion.div>
        {analyzeError && (
          <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="glass rounded-xl p-4 border border-danger/30 flex items-center gap-3">
            <AlertTriangle className="w-5 h-5 text-danger flex-shrink-0" />
            <p className="text-sm text-danger flex-1">{analyzeError}</p>
            <button onClick={startAnalysis} className="text-xs text-accent-light hover:underline cursor-pointer">Retry</button>
          </motion.div>
        )}
        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="glass-light rounded-lg p-12 text-center">
          <div className="w-20 h-20 rounded-full gradient-accent flex items-center justify-center mx-auto mb-6">
            <Activity className="w-10 h-10 text-white" />
          </div>
          {maxReachedStep >= 2 ? (
            <>
              <h3 className="text-xl font-semibold text-foreground mb-3">Re-run Pre-Migration Analysis</h3>
              <p className="text-sm text-muted mb-3 max-w-md mx-auto">
                {isLocalFolder ? 'Folder uploaded: ' : 'Repository connected: '}
                <span className="text-foreground font-mono text-xs">{isLocalFolder ? (folderName || uploadId) : repoUrl.replace(/^https?:\/\//, '')}</span>
              </p>
              <p className="text-xs text-muted mb-8 max-w-md mx-auto">
                Previous analysis results were not found in the database. Click below to re-run the analysis.
              </p>
            </>
          ) : (
            <>
              <h3 className="text-xl font-semibold text-foreground mb-3">Ready for Pre-Migration Analysis</h3>
              <p className="text-sm text-muted mb-3 max-w-md mx-auto">
                {isLocalFolder ? 'Folder uploaded: ' : 'Repository connected: '}
                <span className="text-foreground font-mono text-xs">{isLocalFolder ? (folderName || uploadId) : repoUrl.replace(/^https?:\/\//, '')}</span>
              </p>
              <p className="text-xs text-muted mb-8 max-w-md mx-auto">
                The analysis will scan all source files, compute complexity metrics, map dependencies, and assess migration risk.
              </p>
            </>
          )}
          <button
            onClick={startAnalysis}
            className="px-8 py-3 rounded-lg gradient-accent text-white text-sm font-semibold hover:opacity-90 transition-opacity flex items-center justify-center gap-2 cursor-pointer mx-auto glow-accent"
          >
            <Play className="w-5 h-5" /> {maxReachedStep >= 2 ? 'Re-run Analysis' : 'Start Pre-Migration Analysis'}
          </button>
        </motion.div>
      </div>
    );
  }

  async function fetchProposals(): Promise<{ entries: DependencyEntry[]; tokens: number }> {
    const deps = (analysis as AnalysisData).dependencies;
    const items = depItems(deps.list);
    const kindByName = new Map(items.map((d) => [d.name.toUpperCase(), d.kind]));
    let entries: DependencyEntry[];
    let tokens = 0;
    try {
      const result = await api.engine.proposeDependencies({
        sourceLanguage,
        targetLanguage: project?.targetLanguage ?? '',
        deps: items.map((d) => d.name),
        customRules: (project?.config as any)?.customRules ?? undefined,
      });
      entries = result.proposals.map(p => {
        const kind = kindByName.get(p.source.toUpperCase()) ?? 'external-lib';
        return {
          id: crypto.randomUUID(),
          source: p.source,
          target: p.target,
          version: p.version,
          notes: p.notes,
          status: 'auto' as const,
          kind,
          // External-lib targets from the LLM are guesses → flag for registry verification.
          verify: kind === 'external-lib',
        };
      });
      tokens = result.accounting?.totals?.totalTokens ?? 0;
    } catch {
      entries = proposeDependencyMappings(sourceLanguage, project?.targetLanguage ?? '', items, null) ?? [];
    }

    // Registry validation: clear `verify` for external libraries confirmed to exist
    // (and align the version when the proposed one is missing). Best-effort, bounded.
    try {
      const eco = ecosystemFor(project?.targetLanguage ?? '');
      const toCheck = entries.filter((e) => e.kind === 'external-lib' && e.verify && e.target);
      if (eco && toCheck.length > 0) {
        const { results } = await api.validateDependencies(eco, toCheck.map((e) => ({ name: e.target, version: e.version })));
        const byName = new Map(results.map((r) => [r.name, r]));
        entries = entries.map((e) => {
          const r = e.target ? byName.get(e.target) : undefined;
          if (!r || !r.exists) return e;
          const versionOk = r.versionOk !== false;
          return {
            ...e,
            verify: false,
            version: versionOk ? e.version : (r.latest ?? e.version),
            notes: e.notes.replace(/\s*[—-]\s*verify the package exists.*$/i, '') + (versionOk ? '' : ` — version adjusted to ${r.latest ?? '?'} (registry-verified)`),
          };
        });
      }
    } catch {
      /* validation is best-effort — leave entries as proposed on failure */
    }

    return { entries, tokens };
  }

  function handleOpenDepMapping() {
    onNavigate?.('dep-mapping', projectId);
  }

  async function handleRegenerateMapping() {
    setProposingDeps(true);
    try {
      const { entries, tokens } = await fetchProposals();
      setDepMapping(entries);
      if (tokens > 0) {
        api.recordStepProgress(projectId, 2, 'completed', maxReachedStep, { actualTokens: tokens }).catch(() => {});
      }
    } finally {
      setProposingDeps(false);
    }
  }

  async function handleConfirmMapping() {
    setSavingMapping(true);
    try {
      if (project?.status === 'completed') {
        await api.updateProject(projectId, {
          status: 'draft',
          maxReachedStep: 2,
          config: { conversionResult: null, activeConversionId: null, dependencyMapping: depMapping, dependencyMappingLocked: true },
        });
      } else {
        await api.updateProject(projectId, { config: { dependencyMapping: depMapping, dependencyMappingLocked: true } });
      }
      setMappingLocked(true);
      onNavigate?.('cost-estimation', projectId);
    } catch {
      onNavigate?.('cost-estimation', projectId);
    } finally {
      setSavingMapping(false);
    }
  }

  async function handleSkipAndStart() {
    if (project?.status === 'completed') {
      await api.updateProject(projectId, {
        status: 'draft',
        maxReachedStep: 2,
        config: { conversionResult: null, activeConversionId: null },
      });
    }
    onNavigate?.('cost-estimation', projectId);
  }

  function handleAddRow() {
    setDepMapping(prev => [...prev, {
      id: crypto.randomUUID(),
      source: '',
      target: '',
      version: '',
      notes: '',
      status: 'added',
    }]);
  }

  function handleRemoveRow(id: string) {
    setDepMapping(prev => prev.flatMap(e => {
      if (e.id !== id) return [e];
      // User-added entries are removed entirely (never existed as proposals)
      if (e.status === 'added') return [];
      // Auto/modified entries are marked removed so the report can show the rejection
      return [{ ...e, status: 'removed' as const }];
    }));
  }

  function handleUndoRemove(id: string) {
    setDepMapping(prev => prev.map(e =>
      e.id === id ? { ...e, status: 'auto' as const } : e
    ));
  }

  function handleUpdateEntry(id: string, field: keyof DependencyEntry, value: string) {
    setDepMapping(prev => prev.map(e => {
      if (e.id !== id) return e;
      const updated = { ...e, [field]: value } as DependencyEntry;
      if (field !== 'status' && e.status === 'auto') updated.status = 'modified';
      return updated;
    }));
  }

  function exportReport() {
    const { scanResults: scan, complexity: comp, dependencies: deps, risk } = analysis!;
    const projectName = project?.name ?? 'Unknown Conversion';
    const srcLang = (project?.sourceLanguage ?? '').toUpperCase() || 'N/A';
    const tgtLang = (project?.targetLanguage ?? '').toUpperCase() || 'N/A';
    const today = new Date().toISOString().slice(0, 10);

    const riskSummary = risk.high > 0
      ? `⚠️ ${risk.high} high-risk file(s) detected — manual review required before migration.`
      : risk.medium > 0
        ? `⚠️ ${risk.medium} medium-risk file(s) — review recommended before migration.`
        : '✅ No high-risk files detected. Migration complexity appears manageable.';

    const complexityRating = comp.avgCyclomatic < 5 ? 'Low' : comp.avgCyclomatic < 10 ? 'Moderate' : 'High';
    const migrationEffort = risk.high > 5 ? 'High' : risk.high > 0 || risk.medium > 3 ? 'Medium' : 'Low';

    const langRows = scan.languages.map(
      l => `| ${l.name} | ${l.files} | ${formatBytes(l.bytes)} | ${l.percentage}% |`
    ).join('\n');

    const extRows = scan.extensions.map(
      e => `| \`${e.ext}\` | ${e.count} | ${e.percentage}% |`
    ).join('\n');

    const highRiskFiles = risk.files.filter(f => f.risk === 'high');
    const medRiskFiles = risk.files.filter(f => f.risk === 'medium');
    const lowRiskFiles = risk.files.filter(f => f.risk === 'low');

    const fileTableRows = risk.files.map(f =>
      `| \`${f.name}\` | \`${f.path}\` | ${f.lines.toLocaleString()} | ${f.codeLines.toLocaleString()} | ${f.complexity} | ${f.nesting} | ${f.dependencies} | ${f.procedures} | ${f.risk.toUpperCase()} |`
    ).join('\n');

    const depList = deps.list.length > 0
      ? depItems(deps.list).map(d => `- \`${d.name}\` _(${KIND_LABEL[d.kind] ?? d.kind})_`).join('\n')
      : '- *(none detected)*';

    const recommendations: string[] = [];
    if (risk.high > 0) recommendations.push(`Prioritise manual review of ${risk.high} high-risk file(s) before starting migration.`);
    if (deps.circularDeps > 0) recommendations.push(`Resolve ${deps.circularDeps} circular dependency/dependencies — these will cause build failures in the target.`);
    if (comp.maxCyclomatic > 20) recommendations.push(`File with cyclomatic complexity ${comp.maxCyclomatic} should be refactored before or during migration.`);
    if (comp.maxNesting > 5) recommendations.push(`Deep nesting (${comp.maxNesting} levels max) detected — flatten control flow in the target language.`);
    if (deps.externalCalls > 0) recommendations.push(`${deps.externalCalls} external call(s) detected — verify all called programs/modules are in scope.`);
    if (scan.totalCommentLines < scan.totalCodeLines * 0.05) recommendations.push('Low comment density — consider documenting business rules before migration to avoid knowledge loss.');
    if (recommendations.length === 0) recommendations.push('No critical blockers detected. Proceed with migration using standard Scriba workflow.');

    const md = `# Pre-Migration Analysis Report

**Project:** ${projectName}
**Source language:** ${srcLang}
**Target language:** ${tgtLang}
**Repository:** ${repoUrl || 'N/A'}
**Branch:** ${branch}
**Report generated:** ${today}
**Analyzed by:** Scriba Platform

---

## Executive Summary

${riskSummary}

| Metric | Value |
| --- | --- |
| Total files scanned | ${scan.totalFiles.toLocaleString()} |
| Source files | ${scan.totalSourceFiles.toLocaleString()} |
| Directories | ${scan.totalDirectories.toLocaleString()} |
| Total size | ${formatBytes(scan.totalSize)} |
| Total lines | ${scan.totalLines.toLocaleString()} |
| Code lines | ${scan.totalCodeLines.toLocaleString()} |
| Comment lines | ${scan.totalCommentLines.toLocaleString()} |
| Blank lines | ${scan.totalBlankLines.toLocaleString()} |
| Overall complexity | ${complexityRating} (avg cyclomatic: ${comp.avgCyclomatic.toFixed(1)}) |
| Estimated migration effort | **${migrationEffort}** |

---

## Recommendations

${recommendations.map((r, i) => `${i + 1}. ${r}`).join('\n')}

---

## Language Distribution

| Language | Files | Size | Share |
| --- | ---: | ---: | ---: |
${langRows}

---

## Complexity Metrics

| Metric | Value |
| --- | ---: |
| Average cyclomatic complexity | ${comp.avgCyclomatic.toFixed(1)} |
| Maximum cyclomatic complexity | ${comp.maxCyclomatic} |
| Average nesting depth | ${comp.avgNesting.toFixed(1)} |
| Maximum nesting depth | ${comp.maxNesting} |
| Average lines per file | ${comp.avgLines} |
| Maximum lines in a file | ${comp.maxLines.toLocaleString()} |
| Total procedures / paragraphs | ${comp.totalProcedures.toLocaleString()} |
| Total sections | ${comp.totalSections.toLocaleString()} |

### Complexity interpretation

- **Low (< 5):** Straightforward logic, low migration risk.
- **Moderate (5–10):** Some branching; verify all paths are covered by tests.
- **High (> 10):** Complex control flow; refactoring recommended before or during migration.
- **Very high (> 20):** Consider splitting the module into smaller units.

---

## Dependency Analysis

| Metric | Value |
| --- | ---: |
| Total dependencies | ${deps.total} |
| Copybooks | ${deps.copybooks} |
| External program calls | ${deps.externalCalls} |
| Manifest packages | ${deps.manifestPackages ?? 0} |
| Circular call dependencies | ${deps.circularDeps} |
| Self-contained files | ${deps.selfContainedFiles ?? deps.orphanFiles} |

### Detected dependencies

${depList}

${deps.circularDeps > 0 ? `> ⚠️ **${deps.circularDeps} circular dependency/dependencies detected.** These must be resolved before migration — circular imports will fail to compile in most target languages.` : ''}

---

## Risk Assessment

| Risk level | Files | Action required |
| --- | ---: | --- |
| 🔴 High | ${risk.high} | Manual review + refactor before migration |
| 🟡 Medium | ${risk.medium} | Review and add tests before migration |
| 🟢 Low | ${risk.low} | Standard migration workflow |

${highRiskFiles.length > 0 ? `### High-risk files\n\n${highRiskFiles.map(f => `- \`${f.name}\` — complexity ${f.complexity}, nesting ${f.nesting}, ${f.lines} lines`).join('\n')}` : ''}

${medRiskFiles.length > 0 ? `\n### Medium-risk files\n\n${medRiskFiles.map(f => `- \`${f.name}\` — complexity ${f.complexity}, nesting ${f.nesting}, ${f.lines} lines`).join('\n')}` : ''}

${lowRiskFiles.length > 0 ? `\n### Low-risk files\n\n${lowRiskFiles.map(f => `- \`${f.name}\``).join('\n')}` : ''}

---

## File Type Distribution

| Extension | Count | Share |
| --- | ---: | ---: |
${extRows}

---

## Line Breakdown

| Category | Lines | Percentage |
| --- | ---: | ---: |
| Code | ${scan.totalCodeLines.toLocaleString()} | ${scan.totalLines > 0 ? ((scan.totalCodeLines / scan.totalLines) * 100).toFixed(1) : 0}% |
| Comments | ${scan.totalCommentLines.toLocaleString()} | ${scan.totalLines > 0 ? ((scan.totalCommentLines / scan.totalLines) * 100).toFixed(1) : 0}% |
| Blank | ${scan.totalBlankLines.toLocaleString()} | ${scan.totalLines > 0 ? ((scan.totalBlankLines / scan.totalLines) * 100).toFixed(1) : 0}% |
| **Total** | **${scan.totalLines.toLocaleString()}** | 100% |

---

## Full File Inventory

| File | Path | Lines | Code | Complexity | Nesting | Deps | Procedures | Risk |
| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | --- |
${fileTableRows}

---

*Report generated by Scriba Platform · ${today}*
`;

    const blob = new Blob([md], { type: 'text/markdown' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `pre-migration-analysis-${projectName.toLowerCase().replace(/\s+/g, '-')}-${today}.md`;
    a.click();
    URL.revokeObjectURL(url);
  }

  // ─── Results ───
  const { scanResults: scan, complexity: comp, dependencies: deps, risk } = analysis;
  const selectedFileData = risk.files.find(f => f.name === selectedFile);

  // ─── Dep-mapping view ───
  if (view === 'dep-mapping') {
    const autoCnt = depMapping.filter(e => e.status === 'auto').length;
    const modifiedCnt = depMapping.filter(e => e.status === 'modified').length;
    const addedCnt = depMapping.filter(e => e.status === 'added').length;
    const removedCnt = depMapping.filter(e => e.status === 'removed').length;
    const activeCnt = depMapping.length - removedCnt;
    return (
      <div className="space-y-6">
        <motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }} className="flex items-center justify-between">
          <div className="flex items-center gap-3">
            <button
              onClick={() => onNavigate?.('pre-analysis', projectId)}
              className="p-1.5 rounded-lg hover:bg-surface-light transition-colors cursor-pointer text-muted hover:text-foreground"
            >
              <ArrowLeft className="w-5 h-5" />
            </button>
            <div>
              <h2 className="text-2xl font-bold text-foreground">Dependency Mapping</h2>
              <p className="text-sm text-muted mt-0.5">Map source dependencies to their target equivalents before migration starts</p>
            </div>
          </div>
          {!mappingLocked && (
            <div className="flex items-center gap-2">
              <button
                onClick={handleRegenerateMapping}
                disabled={proposingDeps}
                className="px-3 py-1.5 rounded-lg border border-border text-xs font-semibold hover:bg-surface-light transition-colors flex items-center gap-2 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
                title="Re-run LLM proposals against current dependencies"
              >
                {proposingDeps ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <RotateCcw className="w-3.5 h-3.5" />}
                {proposingDeps ? 'Generating...' : 'Regenerate'}
              </button>
              <button
                onClick={handleAddRow}
                className="px-3 py-1.5 rounded-lg border border-border text-xs font-semibold hover:bg-surface-light transition-colors flex items-center gap-2 cursor-pointer"
              >
                <Plus className="w-3.5 h-3.5" /> Add dependency
              </button>
            </div>
          )}
        </motion.div>

        {mappingLocked && (
          <motion.div initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-3 border border-success/30 flex items-center justify-between">
            <div className="flex items-center gap-2">
              <Lock className="w-4 h-4 text-success flex-shrink-0" />
              <span className="text-sm text-success font-medium">Mapping confirmed</span>
              <span className="text-xs text-muted">· Locked for migration — editing disabled</span>
            </div>
            <button
              onClick={() => setMappingLocked(false)}
              className="text-xs text-accent-light hover:underline flex items-center gap-1 cursor-pointer"
            >
              <LockOpen className="w-3 h-3" /> Re-edit
            </button>
          </motion.div>
        )}

        <motion.div initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-4 border border-accent/20">
          <p className="text-xs text-muted leading-relaxed">
            Scriba detected <span className="text-foreground font-medium">{deps.list.length}</span> {deps.list.length === 1 ? 'dependency' : 'dependencies'} in your source project.
            Review the proposed target equivalents below. Auto-proposed mappings are generated by the migration engine for{' '}
            <span className="text-foreground font-medium">{sourceLanguage}</span> →{' '}
            <span className="text-foreground font-medium">{project?.targetLanguage ?? 'target'}</span> migrations.
            {!mappingLocked && ' You can edit any field, add entries, or remove ones you don\'t need.'}
            {' '}The confirmed mapping will be passed to the migration engine and included in the final report.
          </p>
        </motion.div>

        {proposingDeps && depMapping.length === 0 && (
          <motion.div initial={{ opacity: 0, y: 6 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-5 border border-accent/20">
            <div className="flex items-center gap-3 mb-3">
              <Loader2 className="w-4 h-4 text-accent-light animate-spin flex-shrink-0" />
              <div>
                <p className="text-sm font-medium text-foreground">Generating dependency proposals…</p>
                <p className="text-xs text-muted">
                  Matching {deps.list.length} {deps.list.length === 1 ? 'dependency' : 'dependencies'} to target equivalents — this can take up to ~25s on large projects.
                </p>
              </div>
            </div>
            <div className="h-1.5 bg-surface-light rounded-full overflow-hidden relative">
              <motion.div
                className="absolute inset-y-0 w-1/3 rounded-full bg-accent"
                animate={{ left: ['-35%', '100%'] }}
                transition={{ duration: 1.2, repeat: Infinity, ease: 'easeInOut' }}
              />
            </div>
          </motion.div>
        )}

        <div className="flex items-center gap-3 flex-wrap">
          {[
            { label: 'Auto-proposed', count: autoCnt, cls: 'text-blue-400 border-blue-400/30 bg-blue-500/10' },
            { label: 'Modified', count: modifiedCnt, cls: 'text-amber-400 border-amber-400/30 bg-amber-500/10' },
            { label: 'Added', count: addedCnt, cls: 'text-green-400 border-green-400/30 bg-green-500/10' },
            { label: 'Rejected', count: removedCnt, cls: 'text-red-400 border-red-400/30 bg-red-500/10' },
          ].filter(s => s.count > 0).map(s => (
            <div key={s.label} className={`flex items-center gap-2 px-3 py-1.5 rounded-lg border text-xs font-medium ${s.cls}`}>
              <span className="font-bold text-sm">{s.count}</span>{s.label}
            </div>
          ))}
          <span className="text-xs text-muted ml-auto">{activeCnt} active {activeCnt === 1 ? 'entry' : 'entries'}</span>
        </div>

        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl overflow-hidden">
          <div className="overflow-x-auto">
            <table className="w-full text-xs">
              <thead>
                <tr className="border-b border-border bg-surface-light/50">
                  <th className="text-left p-3 text-[10px] text-muted uppercase tracking-wider font-semibold w-36">Source</th>
                  <th className="text-left p-3 text-[10px] text-muted uppercase tracking-wider font-semibold w-36">Target</th>
                  <th className="text-left p-3 text-[10px] text-muted uppercase tracking-wider font-semibold w-28">Version</th>
                  <th className="text-left p-3 text-[10px] text-muted uppercase tracking-wider font-semibold">Notes</th>
                  <th className="text-left p-3 text-[10px] text-muted uppercase tracking-wider font-semibold w-24">Status</th>
                  <th className="p-3 w-10" />
                </tr>
              </thead>
              <tbody className="divide-y divide-border/50">
                {depMapping.map((entry, idx) => {
                  const isRemoved = entry.status === 'removed';
                  return (
                    <tr key={entry.id} className={`transition-colors ${isRemoved ? 'opacity-40' : `hover:bg-surface-light/30 ${idx % 2 !== 0 ? 'bg-surface-light/10' : ''}`}`}>
                      <td className="p-3">
                        {entry.status === 'added' && !mappingLocked ? (
                          <input
                            value={entry.source}
                            onChange={e => handleUpdateEntry(entry.id, 'source', e.target.value)}
                            placeholder="source dep"
                            className="w-full bg-transparent border border-border/40 rounded px-2 py-1 text-xs text-foreground placeholder:text-muted/50 focus:outline-none focus:border-accent/50 font-mono"
                          />
                        ) : (
                          <span className={`font-mono text-foreground ${isRemoved ? 'line-through' : ''}`}>{entry.source}</span>
                        )}
                        {entry.kind && (
                          <span className="mt-1 block text-[9px] uppercase tracking-wide text-muted/70">{KIND_LABEL[entry.kind] ?? entry.kind}</span>
                        )}
                      </td>
                      <td className="p-3">
                        {!mappingLocked && !isRemoved ? (
                          <input
                            value={entry.target}
                            onChange={e => handleUpdateEntry(entry.id, 'target', e.target.value)}
                            placeholder="target package"
                            className="w-full bg-transparent border border-border/40 rounded px-2 py-1 text-xs text-foreground placeholder:text-muted/50 focus:outline-none focus:border-accent/50 font-mono"
                          />
                        ) : (
                          <span className={`font-mono text-foreground ${isRemoved ? 'line-through' : ''}`}>{entry.target}</span>
                        )}
                      </td>
                      <td className="p-3">
                        {!mappingLocked && !isRemoved ? (
                          <input
                            value={entry.version}
                            onChange={e => handleUpdateEntry(entry.id, 'version', e.target.value)}
                            placeholder="version"
                            className="w-full bg-transparent border border-border/40 rounded px-2 py-1 text-xs text-foreground placeholder:text-muted/50 focus:outline-none focus:border-accent/50 font-mono"
                          />
                        ) : (
                          <span className={`font-mono text-muted ${isRemoved ? 'line-through' : ''}`}>{entry.version}</span>
                        )}
                        {entry.verify && !isRemoved && (
                          <span className="ml-1 text-[9px] font-semibold uppercase text-amber-400 border border-amber-400/30 bg-amber-500/10 rounded px-1 py-0.5" title="Guessed target — verify it exists in the target registry">verify</span>
                        )}
                      </td>
                      <td className="p-3">
                        {!mappingLocked && !isRemoved ? (
                          <input
                            value={entry.notes}
                            onChange={e => handleUpdateEntry(entry.id, 'notes', e.target.value)}
                            placeholder="notes / rationale"
                            className="w-full bg-transparent border border-border/40 rounded px-2 py-1 text-xs text-foreground placeholder:text-muted/50 focus:outline-none focus:border-accent/50"
                          />
                        ) : (
                          <span className={`text-muted ${isRemoved ? 'line-through' : ''}`}>{entry.notes}</span>
                        )}
                      </td>
                      <td className="p-3">
                        <span className={`text-[10px] font-semibold uppercase tracking-wider px-1.5 py-0.5 rounded border leading-none whitespace-nowrap ${
                          entry.status === 'auto' ? 'text-blue-400 border-blue-400/30 bg-blue-500/10' :
                          entry.status === 'modified' ? 'text-amber-400 border-amber-400/30 bg-amber-500/10' :
                          entry.status === 'added' ? 'text-green-400 border-green-400/30 bg-green-500/10' :
                          'text-red-400 border-red-400/30 bg-red-500/10'
                        }`}>
                          {entry.status}
                        </span>
                      </td>
                      <td className="p-3">
                        {!mappingLocked && (
                          isRemoved ? (
                            <button
                              onClick={() => handleUndoRemove(entry.id)}
                              className="p-1 rounded hover:bg-surface-light transition-colors cursor-pointer text-muted hover:text-foreground"
                              title="Undo removal"
                            >
                              <RotateCcw className="w-3.5 h-3.5" />
                            </button>
                          ) : (
                            <button
                              onClick={() => handleRemoveRow(entry.id)}
                              className="p-1 rounded hover:bg-red-500/15 transition-colors cursor-pointer text-muted hover:text-red-400"
                            >
                              <Trash2 className="w-3.5 h-3.5" />
                            </button>
                          )
                        )}
                      </td>
                    </tr>
                  );
                })}
                {depMapping.length === 0 && (
                  <tr>
                    <td colSpan={6} className="p-8 text-center text-muted text-xs italic">
                      No entries yet. Click "Add dependency" to add one manually.
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </motion.div>

        <div className="flex items-center justify-between pt-2">
          {mappingLocked ? (
            <button
              onClick={() => onNavigate?.('migration-flow', projectId)}
              className="px-6 py-2 rounded-lg gradient-accent text-white text-sm font-semibold hover:opacity-90 transition-opacity flex items-center gap-2 cursor-pointer glow-accent"
            >
              <ArrowRight className="w-4 h-4" /> Continue to Migration
            </button>
          ) : (
            <>
              <button
                onClick={handleSkipAndStart}
                className="px-4 py-2 rounded-lg border border-border text-sm text-muted hover:text-foreground hover:bg-surface-light transition-colors flex items-center gap-2 cursor-pointer"
              >
                Skip — start without mapping
              </button>
              <button
                onClick={handleConfirmMapping}
                disabled={savingMapping}
                className="px-6 py-2 rounded-lg gradient-accent text-white text-sm font-semibold hover:opacity-90 transition-opacity flex items-center gap-2 cursor-pointer glow-accent disabled:opacity-50 disabled:cursor-not-allowed"
              >
                {savingMapping ? <Loader2 className="w-4 h-4 animate-spin" /> : <Lock className="w-4 h-4" />}
                {savingMapping ? 'Saving...' : 'Confirm & Lock Mapping'}
              </button>
            </>
          )}
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }} className="flex items-center justify-between">
        <div>
          <h2 className="text-2xl font-bold text-foreground">Pre-Migration Analysis</h2>
          <p className="text-sm text-muted mt-1">
            Analyzed {analysis.analyzedFileCount} source files from {scan.totalSourceFiles} detected
          </p>
        </div>
        <div className="flex items-center gap-3">
          <button onClick={startAnalysis} className="px-4 py-2 rounded-lg border border-border text-sm font-semibold hover:bg-surface-light transition-colors flex items-center gap-2 cursor-pointer">
            <RotateCcw className="w-4 h-4" /> Re-run analysis
          </button>
          <button onClick={exportReport} className="px-4 py-2 rounded-lg border border-border text-sm font-semibold hover:bg-surface-light transition-colors flex items-center gap-2 cursor-pointer">
            <Download className="w-4 h-4" /> Export Report
          </button>
          <button
            onClick={() => onNavigate?.('dep-mapping', projectId)}
            className="px-4 py-2 rounded-lg gradient-accent text-white text-sm font-semibold hover:opacity-90 transition-opacity flex items-center gap-2 cursor-pointer glow-accent"
          >
            {mappingLocked ? <Lock className="w-4 h-4" /> : <ArrowRight className="w-4 h-4" />}
            {mappingLocked ? 'View Confirmed Mapping' : 'Map Dependencies'}
          </button>
        </div>
      </motion.div>

      {/* ── Stat cards ── */}
      <div className="grid grid-cols-6 gap-3">
        {[
          { icon: FileCode2, label: 'Total Files', value: scan.totalFiles.toLocaleString(), color: 'text-accent-light' },
          { icon: Code, label: 'Source Files', value: scan.totalSourceFiles.toLocaleString(), color: 'text-purple-400' },
          { icon: GitBranch, label: 'Directories', value: scan.totalDirectories.toLocaleString(), color: 'text-cyan-400' },
          { icon: Database, label: 'Total Size', value: formatBytes(scan.totalSize), color: 'text-pink-400' },
          { icon: Layers, label: 'Code Lines', value: scan.totalCodeLines.toLocaleString(), color: 'text-amber-400' },
          { icon: AlertTriangle, label: 'High Risk', value: risk.high.toString(), color: 'text-red-400' },
        ].map((s, i) => {
          const Icon = s.icon;
          return (
            <motion.div key={s.label} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: i * 0.05 }} className="glass rounded-xl p-4 text-center">
              <Icon className={`w-4 h-4 ${s.color} mx-auto mb-2`} />
              <p className="text-xl font-bold text-foreground">{s.value}</p>
              <p className="text-[9px] text-muted uppercase tracking-wider">{s.label}</p>
            </motion.div>
          );
        })}
      </div>

      {/* ── Line breakdown bar ── */}
      <motion.div initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-4">
        <h3 className="text-sm font-semibold text-foreground mb-3">Line Breakdown</h3>
        <div className="flex h-3 rounded-full overflow-hidden mb-2">
          <div className="bg-accent" style={{ width: `${scan.totalLines > 0 ? (scan.totalCodeLines / scan.totalLines * 100) : 0}%` }} title="Code" />
          <div className="bg-green-500" style={{ width: `${scan.totalLines > 0 ? (scan.totalCommentLines / scan.totalLines * 100) : 0}%` }} title="Comments" />
          <div className="bg-surface-light" style={{ width: `${scan.totalLines > 0 ? (scan.totalBlankLines / scan.totalLines * 100) : 0}%` }} title="Blank" />
        </div>
        <div className="flex items-center gap-6 text-[10px] text-muted">
          <span className="flex items-center gap-1"><div className="w-2 h-2 rounded-full bg-accent" /> Code: {scan.totalCodeLines.toLocaleString()}</span>
          <span className="flex items-center gap-1"><div className="w-2 h-2 rounded-full bg-green-500" /> Comments: {scan.totalCommentLines.toLocaleString()}</span>
          <span className="flex items-center gap-1"><div className="w-2 h-2 rounded-full bg-surface-light" /> Blank: {scan.totalBlankLines.toLocaleString()}</span>
          <span className="ml-auto text-foreground font-medium">Total: {scan.totalLines.toLocaleString()} lines</span>
        </div>
      </motion.div>

      <div className="grid grid-cols-2 gap-4">
        {/* ── Language Distribution ── */}
        <motion.div initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }} className="glass rounded-xl p-5">
          <h3 className="text-base font-semibold text-foreground mb-4 flex items-center gap-2">
            <FileCode2 className="w-4 h-4 text-accent-light" /> Language Distribution
          </h3>
          {scan.languages.length > 0 && (
            <div className="flex h-2 rounded-full overflow-hidden mb-4">
              {scan.languages.map(l => (
                <div key={l.name} style={{ width: `${l.percentage}%`, backgroundColor: langColors[l.name] || '#6e7681' }} />
              ))}
            </div>
          )}
          <div className="space-y-2.5">
            {scan.languages.map(lang => (
              <div key={lang.name} className="flex items-center gap-3">
                <div className="w-2.5 h-2.5 rounded-full flex-shrink-0" style={{ backgroundColor: langColors[lang.name] || '#6e7681' }} />
                <span className="text-xs text-foreground w-24">{lang.name}</span>
                <div className="flex-1 h-2 bg-surface-light rounded-full overflow-hidden">
                  <div className="h-full rounded-full" style={{ width: `${lang.percentage}%`, backgroundColor: langColors[lang.name] || '#6e7681' }} />
                </div>
                <span className="text-xs text-foreground font-mono w-12 text-right">{lang.percentage}%</span>
                <span className="text-[10px] text-muted w-16 text-right">{lang.files} files</span>
              </div>
            ))}
          </div>
        </motion.div>

        {/* ── Dependencies ── */}
        <motion.div initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} className="glass rounded-xl p-5">
          <h3 className="text-base font-semibold text-foreground mb-4 flex items-center gap-2">
            <Network className="w-4 h-4 text-accent-light" /> Dependency Analysis
          </h3>
          <div className="grid grid-cols-2 gap-3 mb-4">
            {[
              { label: 'Total Dependencies', value: deps.total, color: 'text-accent-light' },
              { label: 'Copybooks', value: deps.copybooks, color: 'text-purple-400' },
              { label: 'External Calls', value: deps.externalCalls, color: 'text-cyan-400' },
              { label: 'Manifest Packages', value: deps.manifestPackages ?? 0, color: 'text-emerald-400' },
              { label: 'Circular Dependencies', value: deps.circularDeps, color: deps.circularDeps > 0 ? 'text-red-400' : 'text-green-400' },
            ].map(d => (
              <div key={d.label} className="glass-light rounded-lg p-3 text-center">
                <p className={`text-lg font-bold ${d.color}`}>{d.value}</p>
                <p className="text-[9px] text-muted uppercase tracking-wider">{d.label}</p>
              </div>
            ))}
          </div>
          {deps.list.length > 0 && (
            <div>
              <p className="text-[10px] text-muted uppercase tracking-wider mb-2">Detected Dependencies</p>
              <div className="flex flex-wrap gap-1 max-h-[120px] overflow-y-auto">
                {depItems(deps.list).map((d, i) => (
                  <span key={i} title={KIND_LABEL[d.kind] ?? d.kind} className="px-2 py-0.5 rounded-full bg-surface-light text-[10px] text-muted font-mono">{d.name}</span>
                ))}
              </div>
              {deps.truncated && (
                <p className="text-[10px] text-muted/60 mt-1 italic">+{deps.total - (deps.shown ?? depItems(deps.list).length)} more not shown</p>
              )}
            </div>
          )}
          {deps.graph?.copybookFanIn && deps.graph.copybookFanIn.length > 0 && (
            <div className="mt-4">
              <p className="text-[10px] text-muted uppercase tracking-wider mb-2">Most-shared copybooks (fan-in)</p>
              <div className="space-y-1">
                {deps.graph.copybookFanIn.slice(0, 6).map(c => (
                  <div key={c.name} className="flex items-center gap-2">
                    <span className="font-mono text-[11px] text-foreground w-32 truncate" title={c.name}>{c.name}</span>
                    <div className="flex-1 h-1.5 rounded-full bg-surface-light overflow-hidden">
                      <div className="h-full rounded-full bg-purple-400" style={{ width: `${Math.min(100, (c.count / (deps.graph!.copybookFanIn[0]?.count || 1)) * 100)}%` }} />
                    </div>
                    <span className="text-[10px] text-muted w-10 text-right">{c.count}×</span>
                  </div>
                ))}
              </div>
              {deps.graph.edges.length > 0 && (
                <p className="text-[10px] text-muted/70 mt-2">{deps.graph.edges.length} program-call edge{deps.graph.edges.length === 1 ? '' : 's'} mapped between modules.</p>
              )}
            </div>
          )}
        </motion.div>
      </div>

      <div className="grid grid-cols-2 gap-4">
        {/* ── Complexity Metrics ── */}
        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-5">
          <h3 className="text-base font-semibold text-foreground mb-4 flex items-center gap-2">
            <Layers className="w-4 h-4 text-accent-light" /> Complexity Metrics
          </h3>
          <div className="grid grid-cols-2 gap-3">
            {[
              { label: 'Avg Cyclomatic', value: comp.avgCyclomatic.toFixed(1) },
              { label: 'Max Cyclomatic', value: comp.maxCyclomatic },
              { label: 'Avg Nesting', value: `${comp.avgNesting.toFixed(1)} levels` },
              { label: 'Max Nesting', value: `${comp.maxNesting} levels` },
              { label: 'Avg Lines/File', value: comp.avgLines },
              { label: 'Max Lines/File', value: comp.maxLines },
              { label: 'Procedures', value: comp.totalProcedures },
              { label: 'Sections', value: comp.totalSections },
            ].map(m => (
              <div key={m.label} className="glass-light rounded-lg p-3">
                <p className="text-[10px] text-muted uppercase tracking-wider">{m.label}</p>
                <p className="text-sm font-medium text-foreground">{typeof m.value === 'number' ? m.value.toLocaleString() : m.value}</p>
              </div>
            ))}
          </div>
        </motion.div>

        {/* ── Risk Assessment ── */}
        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.1 }} className="glass rounded-xl p-5">
          <h3 className="text-base font-semibold text-foreground mb-4 flex items-center gap-2">
            <AlertTriangle className="w-4 h-4 text-amber-400" /> Risk Assessment
          </h3>
          {/* Risk summary */}
          <div className="grid grid-cols-3 gap-3 mb-4">
            <div className="glass-light rounded-lg p-3 text-center border-l-2 border-red-400">
              <p className="text-lg font-bold text-red-400">{risk.high}</p>
              <p className="text-[9px] text-muted uppercase">High Risk</p>
            </div>
            <div className="glass-light rounded-lg p-3 text-center border-l-2 border-amber-400">
              <p className="text-lg font-bold text-amber-400">{risk.medium}</p>
              <p className="text-[9px] text-muted uppercase">Medium Risk</p>
            </div>
            <div className="glass-light rounded-lg p-3 text-center border-l-2 border-green-400">
              <p className="text-lg font-bold text-green-400">{risk.low}</p>
              <p className="text-[9px] text-muted uppercase">Low Risk</p>
            </div>
          </div>
          {/* File list */}
          <div className="space-y-1.5 max-h-[200px] overflow-y-auto">
            {risk.files.map(file => (
              <div
                key={file.path}
                onClick={() => setSelectedFile(selectedFile === file.name ? null : file.name)}
                className={`p-2.5 rounded-lg border cursor-pointer transition-all text-xs ${selectedFile === file.name ? 'border-accent/50 bg-accent/5' : 'border-border hover:border-accent/30'}`}
              >
                <div className="flex items-center justify-between">
                  <span className="text-foreground font-medium truncate flex-1 mr-2 font-mono">{file.name}</span>
                  <span className="text-[10px] text-muted mr-2">C:{file.complexity}</span>
                  <span className={`text-[10px] px-1.5 py-0.5 rounded-full font-medium ${riskColor(file.risk)}`}>{file.risk}</span>
                </div>
              </div>
            ))}
          </div>
        </motion.div>
      </div>

      {/* ── Selected file details ── */}
      {selectedFileData && (
        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-5">
          <div className="flex items-center justify-between mb-4">
            <h3 className="text-base font-semibold text-foreground flex items-center gap-2">
              <Eye className="w-4 h-4 text-accent-light" /> File Analysis: <span className="font-mono text-accent-light">{selectedFileData.name}</span>
            </h3>
            <button onClick={() => setSelectedFile(null)} className="p-1.5 rounded hover:bg-surface-light cursor-pointer">
              <X className="w-4 h-4 text-muted" />
            </button>
          </div>
          <div className="grid grid-cols-5 gap-3">
            <div className="glass-light rounded-lg p-3">
              <p className="text-[10px] text-muted uppercase tracking-wider">Size</p>
              <p className="text-sm font-medium text-foreground">{formatBytes(selectedFileData.size)}</p>
            </div>
            <div className="glass-light rounded-lg p-3">
              <p className="text-[10px] text-muted uppercase tracking-wider">Lines</p>
              <p className="text-sm font-medium text-foreground">{selectedFileData.lines}</p>
            </div>
            <div className="glass-light rounded-lg p-3">
              <p className="text-[10px] text-muted uppercase tracking-wider">Code Lines</p>
              <p className="text-sm font-medium text-foreground">{selectedFileData.codeLines}</p>
            </div>
            <div className="glass-light rounded-lg p-3">
              <p className="text-[10px] text-muted uppercase tracking-wider">Complexity</p>
              <p className="text-sm font-medium text-foreground">{selectedFileData.complexity}</p>
            </div>
            <div className="glass-light rounded-lg p-3">
              <p className="text-[10px] text-muted uppercase tracking-wider">Nesting</p>
              <p className="text-sm font-medium text-foreground">{selectedFileData.nesting} levels</p>
            </div>
          </div>
          <div className="mt-4 glass-light rounded-lg p-4">
            <p className="text-[10px] text-muted uppercase tracking-wider mb-2">Risk Factors</p>
            <ul className="space-y-1 text-xs text-muted">
              {selectedFileData.complexity > 20 && <li className="flex items-center gap-2"><AlertTriangle className="w-3 h-3 text-red-400" /> High cyclomatic complexity ({selectedFileData.complexity})</li>}
              {selectedFileData.complexity > 10 && selectedFileData.complexity <= 20 && <li className="flex items-center gap-2"><AlertTriangle className="w-3 h-3 text-amber-400" /> Moderate cyclomatic complexity ({selectedFileData.complexity})</li>}
              {selectedFileData.nesting > 4 && <li className="flex items-center gap-2"><AlertTriangle className="w-3 h-3 text-amber-400" /> Deep nesting ({selectedFileData.nesting} levels)</li>}
              {selectedFileData.codeLines > 500 && <li className="flex items-center gap-2"><AlertTriangle className="w-3 h-3 text-amber-400" /> Large file ({selectedFileData.codeLines} code lines)</li>}
              {selectedFileData.dependencies > 0 && <li className="flex items-center gap-2"><Network className="w-3 h-3 text-purple-400" /> {selectedFileData.dependencies} dependencies</li>}
              {selectedFileData.procedures > 0 && <li className="flex items-center gap-2"><Layers className="w-3 h-3 text-cyan-400" /> {selectedFileData.procedures} procedures/paragraphs</li>}
              {selectedFileData.risk === 'low' && <li className="flex items-center gap-2"><CheckCircle2 className="w-3 h-3 text-green-400" /> Low complexity — straightforward migration expected</li>}
            </ul>
          </div>
        </motion.div>
      )}

      {/* ── File extensions ── */}
      <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="glass rounded-xl p-5">
        <h3 className="text-base font-semibold text-foreground mb-4 flex items-center gap-2">
          <FileCode2 className="w-4 h-4 text-purple-400" /> File Type Distribution
        </h3>
        <div className="grid grid-cols-8 gap-2">
          {scan.extensions.slice(0, 16).map(e => (
            <div key={e.ext} className="glass-light rounded-lg p-2.5 text-center">
              <p className="text-xs font-mono text-foreground font-medium">{e.ext}</p>
              <p className="text-[10px] text-muted">{e.count} ({e.percentage}%)</p>
            </div>
          ))}
        </div>
      </motion.div>
    </div>
  );
}
