import { Badge } from '@/components/ui/badge';
import { Plus, Minus, Edit, Check } from 'lucide-react';
import { formatFieldValue } from '@/lib/submissionChangeDetection';
import { useState } from 'react';
import { Button } from '@/components/ui/button';

interface ArrayFieldDiffProps {
  fieldName: string;
  oldArray: unknown[];
  newArray: unknown[];
  compact?: boolean;
}

interface ArrayDiffItem {
  type: 'added' | 'removed' | 'modified' | 'unchanged';
  oldValue?: unknown;
  newValue?: unknown;
  index: number;
}

export function ArrayFieldDiff({ fieldName, oldArray, newArray, compact = false }: ArrayFieldDiffProps) {
  const [showUnchanged, setShowUnchanged] = useState(false);
  
  // Compute array differences
  const differences = computeArrayDiff(oldArray || [], newArray || []);
  const changedItems = differences.filter(d => d.type !== 'unchanged');
  const unchangedCount = differences.filter(d => d.type === 'unchanged').length;
  const totalChanges = changedItems.length;

  if (compact) {
    return (
      <Badge variant="outline" className="text-blue-600 dark:text-blue-400">
        <Edit className="h-3 w-3 mr-1" />
        {fieldName} ({totalChanges} changes)
      </Badge>
    );
  }

  return (
    <div className="flex flex-col gap-2 p-3 rounded-md bg-muted/30 border">
      <div className="flex items-center justify-between">
        <div className="text-sm font-medium">
          {fieldName} ({differences.length} items, {totalChanges} changed)
        </div>
        {unchangedCount > 0 && (
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setShowUnchanged(!showUnchanged)}
            className="h-6 text-xs"
          >
            {showUnchanged ? 'Hide' : 'Show'} {unchangedCount} unchanged
          </Button>
        )}
      </div>

      <div className="flex flex-col gap-1">
        {differences.map((diff, idx) => {
          if (diff.type === 'unchanged' && !showUnchanged) {
            return null;
          }

          return (
            <ArrayDiffItemDisplay key={idx} diff={diff} />
          );
        })}
      </div>
    </div>
  );
}

function ArrayDiffItemDisplay({ diff }: { diff: ArrayDiffItem }) {
  const isObject = typeof diff.newValue === 'object' || typeof diff.oldValue === 'object';

  switch (diff.type) {
    case 'added':
      return (
        <div className="flex items-start gap-2 p-2 rounded bg-green-500/10 border border-green-500/20">
          <Plus className="h-4 w-4 text-green-600 dark:text-green-400 mt-0.5 flex-shrink-0" />
          <div className="flex-1 text-sm">
            {isObject ? (
              <ObjectDisplay value={diff.newValue} />
            ) : (
              <span className="text-green-600 dark:text-green-400">
                {formatFieldValue(diff.newValue)}
              </span>
            )}
          </div>
        </div>
      );

    case 'removed':
      return (
        <div className="flex items-start gap-2 p-2 rounded bg-red-500/10 border border-red-500/20">
          <Minus className="h-4 w-4 text-red-600 dark:text-red-400 mt-0.5 flex-shrink-0" />
          <div className="flex-1 text-sm">
            {isObject ? (
              <ObjectDisplay value={diff.oldValue} className="line-through opacity-75" />
            ) : (
              <span className="text-red-600 dark:text-red-400 line-through">
                {formatFieldValue(diff.oldValue)}
              </span>
            )}
          </div>
        </div>
      );

    case 'modified':
      return (
        <div className="flex flex-col gap-1 p-2 rounded bg-amber-500/10 border border-amber-500/20">
          <div className="flex items-start gap-2">
            <Edit className="h-4 w-4 text-amber-600 dark:text-amber-400 mt-0.5 flex-shrink-0" />
            <div className="flex-1 text-sm">
              <div className="text-red-600 dark:text-red-400 line-through mb-1">
                {isObject ? (
                  <ObjectDisplay value={diff.oldValue} />
                ) : (
                  formatFieldValue(diff.oldValue)
                )}
              </div>
              <div className="text-green-600 dark:text-green-400">
                {isObject ? (
                  <ObjectDisplay value={diff.newValue} />
                ) : (
                  formatFieldValue(diff.newValue)
                )}
              </div>
            </div>
          </div>
        </div>
      );

    case 'unchanged':
      return (
        <div className="flex items-start gap-2 p-2 rounded bg-muted/20">
          <Check className="h-4 w-4 text-muted-foreground mt-0.5 flex-shrink-0" />
          <div className="flex-1 text-sm text-muted-foreground">
            {isObject ? (
              <ObjectDisplay value={diff.newValue} />
            ) : (
              formatFieldValue(diff.newValue)
            )}
          </div>
        </div>
      );
  }
}

function ObjectDisplay({ value, className = '' }: { value: unknown; className?: string }) {
  if (!value || typeof value !== 'object') {
    return <span className={className}>{formatFieldValue(value)}</span>;
  }

  return (
    <div className={`space-y-0.5 ${className}`}>
      {Object.entries(value).map(([key, val]) => (
        <div key={key} className="flex gap-2">
          <span className="font-medium capitalize">{key.replace(/_/g, ' ')}:</span>
          <span>{formatFieldValue(val)}</span>
        </div>
      ))}
    </div>
  );
}

/**
 * Compute differences between two arrays
 */
function computeArrayDiff(oldArray: unknown[], newArray: unknown[]): ArrayDiffItem[] {
  const results: ArrayDiffItem[] = [];
  const maxLength = Math.max(oldArray.length, newArray.length);

  // Simple position-based comparison
  for (let i = 0; i < maxLength; i++) {
    const oldValue = i < oldArray.length ? oldArray[i] : undefined;
    const newValue = i < newArray.length ? newArray[i] : undefined;

    if (oldValue === undefined && newValue !== undefined) {
      // Added
      results.push({ type: 'added', newValue, index: i });
    } else if (oldValue !== undefined && newValue === undefined) {
      // Removed
      results.push({ type: 'removed', oldValue, index: i });
    } else if (!isEqual(oldValue, newValue)) {
      // Modified
      results.push({ type: 'modified', oldValue, newValue, index: i });
    } else {
      // Unchanged
      results.push({ type: 'unchanged', oldValue, newValue, index: i });
    }
  }

  return results;
}

/**
 * Deep equality check
 */
function isEqual(a: unknown, b: unknown): boolean {
  if (a === b) return true;
  if (a == null || b == null) return a === b;
  if (typeof a !== typeof b) return false;

  if (typeof a === 'object') {
    if (Array.isArray(a) && Array.isArray(b)) {
      if (a.length !== b.length) return false;
      return a.every((item, i) => isEqual(item, b[i]));
    }

    const keysA = Object.keys(a);
    const keysB = Object.keys(b);
    if (keysA.length !== keysB.length) return false;

    return keysA.every(key => isEqual(a[key], b[key]));
  }

  return false;
}
