'use client';

import { useState, useEffect, useCallback } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
  History,
  GitCompare,
  ChevronRight,
  FileCode,
  Plus,
  Minus,
  Loader2,
  AlertCircle,
  Clock,
  Code,
  Database,
  X,
} from 'lucide-react';
import type { GenerationVersion, DiffResult, DiffLine } from '@/lib/dark-factory/version-history';
import { computeDiff } from '@/lib/dark-factory/version-history';

interface VersionHistoryPanelProps {
  projectId: string;
  onClose: () => void;
}

interface VersionListItem {
  id: string;
  taskId: string;
  prompt: string;
  status: string;
  artifactCount: number;
  createdAt: string;
}

export function VersionHistoryPanel({ projectId, onClose }: VersionHistoryPanelProps) {
  const [versions, setVersions] = useState<VersionListItem[]>([]);
  const [loading, setLoading] = useState(true);
  const [selectedA, setSelectedA] = useState<string | null>(null);
  const [selectedB, setSelectedB] = useState<string | null>(null);
  const [diffResults, setDiffResults] = useState<DiffResult[] | null>(null);
  const [diffLoading, setDiffLoading] = useState(false);
  const [expandedFile, setExpandedFile] = useState<string | null>(null);
  const [mode, setMode] = useState<'list' | 'diff'>('list');

  useEffect(() => {
    fetchVersions();
  }, [projectId]);

  const fetchVersions = async () => {
    setLoading(true);
    try {
      const res = await fetch(`/api/dark-factory/tasks?projectId=${projectId}&limit=50`);
      if (res.ok) {
        const data = await res.json();
        const tasks = (data.data || []).filter(
          (t: { status: string; artifactCount?: number }) =>
            ['awaiting_approval', 'completed', 'deployed'].includes(t.status) &&
            (t.artifactCount || 0) > 0
        );
        setVersions(
          tasks.map((t: { id: string; status: string; prompt?: string; request?: { prompt: string }; artifactCount?: number; createdAt: string }) => ({
            id: t.id,
            taskId: t.id,
            prompt: t.prompt || t.request?.prompt || 'Unknown prompt',
            status: t.status,
            artifactCount: t.artifactCount || 0,
            createdAt: t.createdAt,
          }))
        );
      }
    } catch (err) {
      console.error('Failed to fetch versions:', err);
    } finally {
      setLoading(false);
    }
  };

  const loadDiff = useCallback(async () => {
    if (!selectedA || !selectedB || selectedA === selectedB) return;
    setDiffLoading(true);
    setDiffResults(null);
    setMode('diff');

    try {
      // Fetch artifacts for both versions
      const [resA, resB] = await Promise.all([
        fetch(`/api/dark-factory/status/${selectedA}`),
        fetch(`/api/dark-factory/status/${selectedB}`),
      ]);

      if (!resA.ok || !resB.ok) throw new Error('Failed to fetch version data');

      const [dataA, dataB] = await Promise.all([resA.json(), resB.json()]);

      // Build artifact maps
      const artifactsA: Array<{ id: string; path: string; content: string }> = [];
      const artifactsB: Array<{ id: string; path: string; content: string }> = [];

      // Load full content for each artifact
      for (const art of dataA.artifacts || []) {
        const r = await fetch(`/api/dark-factory/artifacts/${art.id}`);
        if (r.ok) {
          const d = await r.json();
          artifactsA.push({ id: d.id, path: d.path, content: d.content || '' });
        }
      }
      for (const art of dataB.artifacts || []) {
        const r = await fetch(`/api/dark-factory/artifacts/${art.id}`);
        if (r.ok) {
          const d = await r.json();
          artifactsB.push({ id: d.id, path: d.path, content: d.content || '' });
        }
      }

      // Compute diffs
      const diffs: DiffResult[] = [];
      const mapA = new Map(artifactsA.map(a => [a.path, a.content]));
      const mapB = new Map(artifactsB.map(a => [a.path, a.content]));

      // Files in B (new version)
      for (const [path, contentB] of mapB) {
        const contentA = mapA.get(path);
        if (contentA === undefined) {
          // New file
          const lines = contentB.split('\n');
          diffs.push({
            path,
            hunks: [{ oldStart: 0, newStart: 1, lines: lines.map((l, i) => ({ type: 'added' as const, content: l, lineNumber: i + 1 })) }],
            additions: lines.length,
            deletions: 0,
            isNew: true,
            isDeleted: false,
          });
        } else {
          // Modified
          const diffLines = computeDiff(contentA, contentB);
          const additions = diffLines.filter(l => l.type === 'added').length;
          const deletions = diffLines.filter(l => l.type === 'removed').length;
          if (additions > 0 || deletions > 0) {
            diffs.push({
              path,
              hunks: [{ oldStart: 1, newStart: 1, lines: diffLines }],
              additions,
              deletions,
              isNew: false,
              isDeleted: false,
            });
          }
          mapA.delete(path);
        }
      }

      // Deleted files
      for (const [path, contentA] of mapA) {
        if (!mapB.has(path)) {
          const lines = contentA.split('\n');
          diffs.push({
            path,
            hunks: [{ oldStart: 1, newStart: 0, lines: lines.map((l, i) => ({ type: 'removed' as const, content: l, lineNumber: i + 1 })) }],
            additions: 0,
            deletions: lines.length,
            isNew: false,
            isDeleted: true,
          });
        }
      }

      setDiffResults(diffs);
      if (diffs.length > 0) setExpandedFile(diffs[0].path);
    } catch (err) {
      console.error('Diff computation failed:', err);
    } finally {
      setDiffLoading(false);
    }
  }, [selectedA, selectedB]);

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm p-4"
      onClick={onClose}
    >
      <motion.div
        initial={{ scale: 0.95, opacity: 0 }}
        animate={{ scale: 1, opacity: 1 }}
        exit={{ scale: 0.95, opacity: 0 }}
        className="bg-brand-bg-elevated border border-brand-secondary/30 rounded-2xl max-w-5xl w-full max-h-[85vh] flex flex-col shadow-2xl"
        onClick={(e) => e.stopPropagation()}
      >
        {/* Header */}
        <div className="flex items-center justify-between p-6 border-b border-white/10">
          <div className="flex items-center gap-3">
            <History className="w-6 h-6 text-brand-secondary-light" />
            <h2 className="text-2xl font-bold text-white">Version History</h2>
          </div>
          <div className="flex items-center gap-2">
            {mode === 'diff' && (
              <button
                onClick={() => { setMode('list'); setDiffResults(null); }}
                className="px-3 py-1.5 rounded-lg text-sm text-gray-400 hover:text-white hover:bg-white/10 transition-colors"
              >
                Back to list
              </button>
            )}
            <button
              onClick={onClose}
              className="p-2 rounded-lg hover:bg-white/10 transition-colors"
            >
              <X className="w-5 h-5 text-gray-400" />
            </button>
          </div>
        </div>

        <div className="flex-1 overflow-y-auto">
          {loading ? (
            <div className="flex items-center justify-center py-16">
              <Loader2 className="w-8 h-8 text-brand-secondary-light animate-spin" />
            </div>
          ) : versions.length === 0 ? (
            <div className="text-center py-16">
              <History className="w-10 h-10 text-gray-600 mx-auto mb-3" />
              <p className="text-gray-400">No generation versions found for this project</p>
              <p className="text-gray-500 text-sm mt-1">Generate some code first to see version history</p>
            </div>
          ) : mode === 'list' ? (
            <div className="p-6">
              {/* Selection hint */}
              <div className="mb-4 p-3 rounded-lg bg-brand-secondary/10 border border-brand-secondary/20 text-sm text-brand-secondary-light">
                <GitCompare className="w-4 h-4 inline mr-2" />
                Select two versions to compare. Click the left column for the &quot;old&quot; version and the right column for the &quot;new&quot; version.
              </div>

              {/* Version list */}
              <div className="space-y-2">
                {versions.map((v, idx) => (
                  <div
                    key={v.id}
                    className={`flex items-center gap-3 p-4 rounded-xl border transition-all ${
                      selectedA === v.id || selectedB === v.id
                        ? 'bg-brand-secondary/10 border-brand-secondary/30'
                        : 'bg-white/5 border-white/10 hover:border-white/20'
                    }`}
                  >
                    {/* A selector */}
                    <button
                      onClick={() => setSelectedA(selectedA === v.id ? null : v.id)}
                      className={`flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold transition-all border ${
                        selectedA === v.id
                          ? 'bg-red-500/20 border-red-500/40 text-red-400'
                          : 'bg-white/5 border-white/10 text-gray-500 hover:text-white'
                      }`}
                      title="Select as old version"
                    >
                      A
                    </button>
                    {/* B selector */}
                    <button
                      onClick={() => setSelectedB(selectedB === v.id ? null : v.id)}
                      className={`flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold transition-all border ${
                        selectedB === v.id
                          ? 'bg-green-500/20 border-green-500/40 text-green-400'
                          : 'bg-white/5 border-white/10 text-gray-500 hover:text-white'
                      }`}
                      title="Select as new version"
                    >
                      B
                    </button>

                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2">
                        <span className="text-white font-medium text-sm">v{versions.length - idx}</span>
                        <span className={`px-2 py-0.5 rounded text-xs ${
                          v.status === 'completed' || v.status === 'deployed'
                            ? 'bg-green-500/15 text-green-400'
                            : 'bg-yellow-500/15 text-yellow-400'
                        }`}>
                          {v.status}
                        </span>
                      </div>
                      <p className="text-sm text-gray-400 truncate mt-0.5">{v.prompt}</p>
                    </div>

                    <div className="flex items-center gap-4 text-xs text-gray-500 flex-shrink-0">
                      <span className="flex items-center gap-1">
                        <Code className="w-3.5 h-3.5" />
                        {v.artifactCount}
                      </span>
                      <span className="flex items-center gap-1">
                        <Clock className="w-3.5 h-3.5" />
                        {new Date(v.createdAt).toLocaleDateString()}
                      </span>
                    </div>
                  </div>
                ))}
              </div>

              {/* Compare button */}
              {selectedA && selectedB && selectedA !== selectedB && (
                <motion.div
                  initial={{ opacity: 0, y: 10 }}
                  animate={{ opacity: 1, y: 0 }}
                  className="mt-6 flex justify-center"
                >
                  <button
                    onClick={loadDiff}
                    disabled={diffLoading}
                    className="flex items-center gap-2 px-6 py-3 rounded-xl font-semibold text-white bg-gradient-to-r from-brand-secondary to-brand-deep hover:from-brand-secondary-light hover:to-brand transition-all shadow-lg disabled:opacity-50"
                  >
                    {diffLoading ? (
                      <Loader2 className="w-5 h-5 animate-spin" />
                    ) : (
                      <GitCompare className="w-5 h-5" />
                    )}
                    Compare Versions
                  </button>
                </motion.div>
              )}
            </div>
          ) : (
            /* Diff view */
            <div className="p-6">
              {diffLoading ? (
                <div className="flex items-center justify-center py-16">
                  <Loader2 className="w-8 h-8 text-brand-secondary-light animate-spin" />
                  <span className="ml-3 text-gray-400">Computing diff...</span>
                </div>
              ) : diffResults && diffResults.length === 0 ? (
                <div className="text-center py-16">
                  <AlertCircle className="w-10 h-10 text-gray-600 mx-auto mb-3" />
                  <p className="text-gray-400">No differences found between these versions</p>
                </div>
              ) : diffResults ? (
                <div className="space-y-3">
                  {/* Summary bar */}
                  <div className="flex items-center gap-4 px-4 py-3 rounded-lg bg-white/5 border border-white/10 text-sm">
                    <span className="text-white font-medium">{diffResults.length} file(s) changed</span>
                    <span className="flex items-center gap-1 text-green-400">
                      <Plus className="w-3.5 h-3.5" />
                      {diffResults.reduce((s, d) => s + d.additions, 0)} additions
                    </span>
                    <span className="flex items-center gap-1 text-red-400">
                      <Minus className="w-3.5 h-3.5" />
                      {diffResults.reduce((s, d) => s + d.deletions, 0)} deletions
                    </span>
                  </div>

                  {/* Per-file diffs */}
                  {diffResults.map((diff) => (
                    <div key={diff.path} className="rounded-xl border border-white/10 overflow-hidden">
                      {/* File header */}
                      <button
                        onClick={() => setExpandedFile(expandedFile === diff.path ? null : diff.path)}
                        className="w-full flex items-center gap-3 px-4 py-3 bg-gray-900 hover:bg-gray-800/50 transition-colors text-left"
                      >
                        <ChevronRight
                          className={`w-4 h-4 text-gray-500 transition-transform ${
                            expandedFile === diff.path ? 'rotate-90' : ''
                          }`}
                        />
                        <FileCode className="w-4 h-4 text-brand" />
                        <span className="text-sm text-white font-mono">{diff.path}</span>
                        {diff.isNew && (
                          <span className="px-2 py-0.5 rounded bg-green-500/15 text-green-400 text-xs">new</span>
                        )}
                        {diff.isDeleted && (
                          <span className="px-2 py-0.5 rounded bg-red-500/15 text-red-400 text-xs">deleted</span>
                        )}
                        <span className="ml-auto flex items-center gap-2 text-xs">
                          <span className="text-green-400">+{diff.additions}</span>
                          <span className="text-red-400">-{diff.deletions}</span>
                        </span>
                      </button>

                      {/* Diff content */}
                      <AnimatePresence>
                        {expandedFile === diff.path && (
                          <motion.div
                            initial={{ height: 0 }}
                            animate={{ height: 'auto' }}
                            exit={{ height: 0 }}
                            className="overflow-hidden"
                          >
                            <div className="overflow-x-auto max-h-[400px] overflow-y-auto bg-gray-950">
                              <pre className="text-xs leading-5">
                                {diff.hunks.flatMap(h => h.lines).slice(0, 200).map((line, i) => (
                                  <div
                                    key={i}
                                    className={`px-4 py-0.5 font-mono whitespace-pre ${
                                      line.type === 'added'
                                        ? 'bg-green-500/10 text-green-300'
                                        : line.type === 'removed'
                                        ? 'bg-red-500/10 text-red-300'
                                        : 'text-gray-400'
                                    }`}
                                  >
                                    <span className="inline-block w-5 text-right mr-3 text-gray-600 select-none">
                                      {line.type === 'added' ? '+' : line.type === 'removed' ? '-' : ' '}
                                    </span>
                                    {line.content}
                                  </div>
                                ))}
                                {diff.hunks.flatMap(h => h.lines).length > 200 && (
                                  <div className="px-4 py-2 text-gray-500 text-center">
                                    ... {diff.hunks.flatMap(h => h.lines).length - 200} more lines
                                  </div>
                                )}
                              </pre>
                            </div>
                          </motion.div>
                        )}
                      </AnimatePresence>
                    </div>
                  ))}
                </div>
              ) : null}
            </div>
          )}
        </div>
      </motion.div>
    </motion.div>
  );
}
