'use client';

import { useMemo, useState } from 'react';
import { useTranslation } from '@/hooks/useTranslation';

type Json = unknown;

type FieldStatus = 'added' | 'removed' | 'modified' | 'unchanged';

interface FieldRow {
  key: string;
  oldValue: Json;
  newValue: Json;
  status: FieldStatus;
}

interface Props {
  oldValue?: Record<string, unknown> | null;
  newValue?: Record<string, unknown> | null;
}

function formatValue(v: Json): string {
  if (v === null || v === undefined) return '—';
  if (typeof v === 'object') return JSON.stringify(v, null, 2);
  return String(v);
}

function isEqual(a: Json, b: Json): boolean {
  if (a === b) return true;
  if (a === null || b === null) return false;
  if (typeof a !== typeof b) return false;
  if (typeof a === 'object') return JSON.stringify(a) === JSON.stringify(b);
  return false;
}

function buildRows(
  oldObj?: Record<string, unknown> | null,
  newObj?: Record<string, unknown> | null,
): FieldRow[] {
  const keys = new Set<string>([
    ...Object.keys(oldObj ?? {}),
    ...Object.keys(newObj ?? {}),
  ]);
  const rows: FieldRow[] = [];
  for (const key of keys) {
    const inOld = oldObj && key in oldObj;
    const inNew = newObj && key in newObj;
    const o = inOld ? oldObj![key] : undefined;
    const n = inNew ? newObj![key] : undefined;
    let status: FieldStatus;
    if (inOld && !inNew) status = 'removed';
    else if (!inOld && inNew) status = 'added';
    else if (isEqual(o, n)) status = 'unchanged';
    else status = 'modified';
    rows.push({ key, oldValue: o, newValue: n, status });
  }
  rows.sort((a, b) => {
    const order = { modified: 0, added: 1, removed: 2, unchanged: 3 };
    if (order[a.status] !== order[b.status]) return order[a.status] - order[b.status];
    return a.key.localeCompare(b.key);
  });
  return rows;
}

const STATUS_STYLE: Record<FieldStatus, { left: string; right: string; tagBg: string }> = {
  added: {
    left: 'bg-gray-50 text-gray-400',
    right: 'bg-green-50 text-green-800',
    tagBg: 'bg-green-100 text-green-700',
  },
  removed: {
    left: 'bg-red-50 text-red-800',
    right: 'bg-gray-50 text-gray-400',
    tagBg: 'bg-red-100 text-red-700',
  },
  modified: {
    left: 'bg-amber-50 text-amber-800',
    right: 'bg-amber-50 text-amber-900',
    tagBg: 'bg-amber-100 text-amber-700',
  },
  unchanged: {
    left: 'bg-white text-gray-600',
    right: 'bg-white text-gray-600',
    tagBg: 'bg-gray-100 text-gray-500',
  },
};

export function AuditDiffView({ oldValue, newValue }: Props) {
  const { t } = useTranslation();
  const [showUnchanged, setShowUnchanged] = useState(false);
  const rows = useMemo(() => buildRows(oldValue, newValue), [oldValue, newValue]);

  const visible = showUnchanged ? rows : rows.filter((r) => r.status !== 'unchanged');
  const unchangedCount = rows.filter((r) => r.status === 'unchanged').length;
  const changedCount = rows.length - unchangedCount;

  const tagLabel: Record<FieldStatus, string> = {
    added: t.audit.detail.diff.tagAdded,
    removed: t.audit.detail.diff.tagRemoved,
    modified: t.audit.detail.diff.tagModified,
    unchanged: t.audit.detail.diff.tagUnchanged,
  };

  if (rows.length === 0) {
    return <p className="text-sm text-gray-500">{t.audit.detail.diff.noChanges}</p>;
  }

  return (
    <div>
      <div className="flex items-center justify-between mb-3">
        <div className="text-sm text-gray-600">
          {t.audit.detail.diff.summary.replace('{count}', String(changedCount))}
          {unchangedCount > 0 && (
            <span className="text-gray-400">
              {t.audit.detail.diff.unchangedSuffix.replace('{count}', String(unchangedCount))}
            </span>
          )}
        </div>
        {unchangedCount > 0 && (
          <button
            onClick={() => setShowUnchanged((v) => !v)}
            className="text-sm text-indigo-600 hover:text-indigo-700"
          >
            {showUnchanged ? t.audit.detail.diff.hideUnchanged : t.audit.detail.diff.showUnchanged}
          </button>
        )}
      </div>
      <div className="grid grid-cols-2 gap-3 text-xs font-medium text-gray-500 mb-2">
        <div className="px-3">{t.audit.detail.oldValue}</div>
        <div className="px-3">{t.audit.detail.newValue}</div>
      </div>
      <div className="space-y-2">
        {visible.map((row) => {
          const style = STATUS_STYLE[row.status];
          return (
            <div key={row.key} className="grid grid-cols-2 gap-3">
              <div className={`rounded-lg border border-gray-100 p-3 ${style.left}`}>
                <div className="flex items-center justify-between mb-1">
                  <span className="text-xs font-mono text-gray-500">{row.key}</span>
                  <span className={`text-[10px] px-1.5 py-0.5 rounded ${style.tagBg}`}>
                    {tagLabel[row.status]}
                  </span>
                </div>
                <pre className="text-xs whitespace-pre-wrap break-all">
                  {row.status === 'added' ? '—' : formatValue(row.oldValue)}
                </pre>
              </div>
              <div className={`rounded-lg border border-gray-100 p-3 ${style.right}`}>
                <div className="flex items-center justify-between mb-1">
                  <span className="text-xs font-mono text-gray-500">{row.key}</span>
                  <span className={`text-[10px] px-1.5 py-0.5 rounded ${style.tagBg}`}>
                    {tagLabel[row.status]}
                  </span>
                </div>
                <pre className="text-xs whitespace-pre-wrap break-all">
                  {row.status === 'removed' ? '—' : formatValue(row.newValue)}
                </pre>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}
