'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useParams } from 'next/navigation';
import {
  Check,
  CheckCheck,
  Download,
  FileDown,
  FileUp,
  Loader2,
  Pencil,
  Search,
  Undo2,
} from 'lucide-react';
import { apiClient, API_BASE_URL } from '@/lib/apiClient';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { useToast } from '@/components/ui/toast';
import { useI18n } from '@/lib/i18n';
import { cn } from '@/lib/utils';

interface Segment {
  id: string;
  segment_index: number;
  source_text: string;
  translated_text: string;
  status: 'pending' | 'approved' | 'edited';
  reviewed_text: string | null;
}

interface SegmentsResponse {
  data: {
    job_id: string;
    file_name: string | null;
    status: string;
    segments: Segment[];
    counts: { total: number; pending: number; approved: number; edited: number };
  };
}

interface RebuildResponse {
  data: { job_id: string; rebuilt: boolean; segments_applied: number; download_url: string };
}

/** Map raw backend errors to something the reviewer can act on. */
function friendlyReviewError(raw: string | undefined, t: (k: string) => string, fallbackKey: string): string | undefined {
  if (!raw) return undefined;
  const r = raw.toLowerCase();
  if (r.includes('401') || r.includes('unauthorized') || r.includes('403')) return t('reviews.error.sessionExpired');
  if (r.includes('404') || r.includes('not found')) return t('reviews.error.notFound');
  if (r.includes('429') || r.includes('rate')) return t('reviews.error.rateLimited');
  if (r.includes('500') || r.includes('server')) return t('reviews.error.server');
  return raw || t(fallbackKey);
}

function authHeaders(): Record<string, string> {
  const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
  const headers: Record<string, string> = {};
  if (token) headers['Authorization'] = `Bearer ${token}`;
  return headers;
}

async function downloadProtected(url: string, filename: string, failMessage: (status: number) => string) {
  const res = await fetch(`${API_BASE_URL}${url}`, { headers: authHeaders() });
  if (!res.ok) throw new Error(failMessage(res.status));
  const blob = await res.blob();
  const objectUrl = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = objectUrl;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(objectUrl);
}

export default function ReviewPage() {
  const params = useParams<{ jobId: string }>();
  const jobId = params?.jobId ?? '';
  const notify = useToast();
  const { t } = useI18n();

  const [segments, setSegments] = useState<Segment[]>([]);
  const [fileName, setFileName] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [draft, setDraft] = useState('');
  const [savingId, setSavingId] = useState<string | null>(null);
  const [isRebuilding, setIsRebuilding] = useState(false);
  const [approveArmed, setApproveArmed] = useState(false);
  const [approvingProgress, setApprovingProgress] = useState<{ current: number; total: number } | null>(null);
  const [isImporting, setIsImporting] = useState(false);
  const [statusFilter, setStatusFilter] = useState<'all' | 'pending' | 'approved' | 'edited'>('all');
  const [searchQuery, setSearchQuery] = useState('');
  const fileInputRef = useRef<HTMLInputElement>(null);

  const load = useCallback(async () => {
    setIsLoading(true);
    setLoadError(null);
    try {
      const res = await apiClient.get<SegmentsResponse>(
        `/api/v1/translations/${jobId}/segments`
      );
      setSegments(res.data.segments);
      setFileName(res.data.file_name);
    } catch (err) {
      setLoadError(
        friendlyReviewError(
          err instanceof Error ? err.message : undefined,
          t,
          'reviews.error.load'
        ) ?? t('reviews.error.load')
      );
    } finally {
      setIsLoading(false);
    }
  }, [jobId, t]);

  useEffect(() => {
    if (jobId) load();
  }, [jobId, load]);

  const counts = useMemo(() => {
    const pending = segments.filter((s) => s.status === 'pending').length;
    const approved = segments.filter((s) => s.status === 'approved').length;
    const edited = segments.filter((s) => s.status === 'edited').length;
    return { total: segments.length, pending, approved, edited };
  }, [segments]);

  const filteredSegments = useMemo(() => {
    return segments.filter((seg) => {
      if (statusFilter !== 'all' && seg.status !== statusFilter) return false;
      if (searchQuery.trim()) {
        const q = searchQuery.toLowerCase();
        const src = (seg.source_text || '').toLowerCase();
        const tgt = (seg.reviewed_text || seg.translated_text || '').toLowerCase();
        return src.includes(q) || tgt.includes(q);
      }
      return true;
    });
  }, [segments, statusFilter, searchQuery]);

  const patchSegment = async (
    id: string,
    body: { reviewed_text?: string; status?: string }
  ) => {
    setSavingId(id);
    try {
      await apiClient.patch(`/api/v1/segments/${id}`, body);
      setSegments((prev) =>
        prev.map((s) =>
          s.id === id
            ? {
                ...s,
                reviewed_text: body.reviewed_text ?? s.reviewed_text,
                status: (body.status ?? s.status) as Segment['status'],
              }
            : s
        )
      );
    } catch (err) {
      notify.error({
        title: t('reviews.error.title'),
        description: friendlyReviewError(err instanceof Error ? err.message : undefined, t, 'reviews.error.update'),
      });
    } finally {
      setSavingId(null);
    }
  };

  const approveAll = async () => {
    // Two-step: the first click arms, the second confirms — no accidental bulk-approve.
    if (!approveArmed) {
      setApproveArmed(true);
      setTimeout(() => setApproveArmed(false), 4000);
      return;
    }
    setApproveArmed(false);
    const pending = segments.filter((s) => s.status === 'pending');
    if (pending.length === 0) return;

    setApprovingProgress({ current: 0, total: pending.length });
    for (let i = 0; i < pending.length; i++) {
      const seg = pending[i];
      await patchSegment(seg.id, { status: 'approved' });
      setApprovingProgress({ current: i + 1, total: pending.length });
    }
    setApprovingProgress(null);

    notify.success({
      title: t('reviews.approvedTitle'),
      description: t('reviews.approvedDesc', { count: pending.length }),
    });
  };

  const rebuild = async () => {
    setIsRebuilding(true);
    try {
      const res = await apiClient.post<RebuildResponse>(
        `/api/v1/translations/${jobId}/rebuild`
      );
      await downloadProtected(
        res.data.download_url,
        `relu_${fileName ?? jobId}`,
        (status) => t('reviews.error.download', { status })
      );
      notify.success({
        title: t('reviews.rebuiltTitle'),
        description: t('reviews.rebuiltDesc', { count: res.data.segments_applied }),
      });
    } catch (err) {
      notify.error({
        title: t('reviews.rebuildFailed'),
        description: friendlyReviewError(err instanceof Error ? err.message : undefined, t, 'reviews.error.update'),
      });
    } finally {
      setIsRebuilding(false);
    }
  };

  const exportXliff = async () => {
    try {
      await downloadProtected(
        `/api/v1/translations/${jobId}/xliff`,
        `${jobId}.xliff`,
        (status) => t('reviews.error.download', { status })
      );
    } catch (err) {
      notify.error({
        title: t('reviews.xliffExportFailed'),
        description: friendlyReviewError(err instanceof Error ? err.message : undefined, t, 'reviews.error.update'),
      });
    }
  };

  const importXliff = async (file: File) => {
    setIsImporting(true);
    try {
      const text = await file.text();
      const res = await fetch(
        `${API_BASE_URL}/api/v1/translations/${jobId}/xliff`,
        {
          method: 'POST',
          headers: { ...authHeaders() },
          body: text,
        }
      );
      if (!res.ok) {
        const json = await res.json().catch(() => ({}));
        throw new Error(
          json?.detail?.message || json?.message || `HTTP ${res.status}`
        );
      }
      const json = await res.json();
      notify.success({
        title: t('reviews.xliffImported'),
        description: t('reviews.xliffImportedDesc', { count: json.data.segments_updated }),
      });
      await load();
    } catch (err) {
      notify.error({
        title: t('reviews.xliffImportFailed'),
        description: friendlyReviewError(err instanceof Error ? err.message : undefined, t, 'reviews.error.update'),
      });
    } finally {
      setIsImporting(false);
      if (fileInputRef.current) fileInputRef.current.value = '';
    }
  };

  const statusBadge = (status: Segment['status']) => {
    if (status === 'approved')
      return <Badge className="bg-green-500/15 text-green-600 border-green-500/30">{t('reviews.status.approved')}</Badge>;
    if (status === 'edited')
      return <Badge className="bg-blue-500/15 text-blue-600 border-blue-500/30">{t('reviews.status.edited')}</Badge>;
    return <Badge variant="outline" className="text-muted-foreground">{t('reviews.status.pending')}</Badge>;
  };

  return (
    <div className="space-y-6">
      <div className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <span className="accent-pill mb-3 block w-fit">{t('reviews.pill')}</span>
          <h1 className="mb-2 text-3xl font-serif font-medium leading-tight tracking-tight text-brand-dark dark:text-white">
            {t('reviews.titleBase')} <span className="italic">{t('reviews.titleAccent')}</span>
          </h1>
          <p className="max-w-xl truncate text-sm text-brand-dark/60 dark:text-white/60">
            {t('reviews.subtitle', {
              file: fileName ?? jobId,
              total: counts.total,
              pending: counts.pending,
              approved: counts.approved,
              edited: counts.edited,
            })}
          </p>
          <p className="max-w-xl text-xs font-light text-brand-dark/50 dark:text-white/50 mt-1">
            {t('reviews.xliffHint')}
          </p>
        </div>

        <div className="flex flex-wrap gap-2">
          <Button
            variant={approveArmed ? 'default' : 'outline'}
            size="sm"
            onClick={approveAll}
            disabled={counts.pending === 0 || !!approvingProgress}
          >
            {approvingProgress ? (
              <>
                <Loader2 className="size-3.5 animate-spin" />
                {t('reviews.approvingProgress', {
                  current: approvingProgress.current,
                  total: approvingProgress.total,
                }) || `Approbation (${approvingProgress.current}/${approvingProgress.total})…`}
              </>
            ) : (
              <>
                <CheckCheck className="size-3.5" />
                {approveArmed
                  ? t('reviews.approveAllConfirm', { count: counts.pending })
                  : t('reviews.approveAll')}
              </>
            )}
          </Button>
          <Button variant="outline" size="sm" onClick={exportXliff} disabled={!segments.length}>
            <FileDown className="size-3.5" /> XLIFF
          </Button>
          <Button
            variant="outline"
            size="sm"
            onClick={() => fileInputRef.current?.click()}
            disabled={isImporting}
          >
            {isImporting ? <Loader2 className="size-3.5 animate-spin" /> : <FileUp className="size-3.5" />}
            {t('reviews.importXliff')}
          </Button>
          <input
            ref={fileInputRef}
            type="file"
            accept=".xliff,.xlf,application/xliff+xml"
            className="hidden"
            onChange={(e) => {
              const f = e.target.files?.[0];
              if (f) importXliff(f);
            }}
          />
          <Button
            size="sm"
            onClick={rebuild}
            disabled={isRebuilding || counts.approved + counts.edited === 0}
            title={
              counts.approved + counts.edited === 0
                ? t('reviews.rebuildDisabledHint')
                : undefined
            }
          >
            {isRebuilding ? <Loader2 className="size-3.5 animate-spin" /> : <Download className="size-3.5" />}
            {t('reviews.rebuild')}
          </Button>
        </div>
      </div>

      {loadError && (
        <div className="rounded-lg border border-red-200/30 bg-red-500/10 px-4 py-3 text-sm text-red-500">
          {loadError}
        </div>
      )}

      {/* ── Filtering and Search bar ──────────────────────────────── */}
      {!isLoading && segments.length > 0 && (
        <div className="flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-3 pt-2">
          {/* Status tabs */}
          <div className="flex flex-wrap gap-1.5 p-1 bg-brand-muted/70 dark:bg-white/5 rounded-xl border border-black/5 dark:border-white/10">
            {[
              { id: 'all', label: t('reviews.filter.all') || 'Tous', count: counts.total },
              { id: 'pending', label: t('reviews.filter.pending') || 'À relire', count: counts.pending },
              { id: 'approved', label: t('reviews.filter.approved') || 'Approuvés', count: counts.approved },
              { id: 'edited', label: t('reviews.filter.edited') || 'Modifiés', count: counts.edited },
            ].map((tab) => (
              <button
                key={tab.id}
                type="button"
                onClick={() => setStatusFilter(tab.id as any)}
                className={cn(
                  'px-3 py-1.5 rounded-lg text-xs font-bold transition-all flex items-center gap-2 cursor-pointer',
                  statusFilter === tab.id
                    ? 'bg-white dark:bg-[#1a1a1a] text-brand-dark dark:text-white shadow-sm'
                    : 'text-brand-dark/50 dark:text-white/50 hover:text-brand-dark dark:hover:text-white'
                )}
              >
                <span>{tab.label}</span>
                <span className={cn(
                  'text-[10px] px-1.5 py-0.5 rounded-full font-semibold',
                  statusFilter === tab.id
                    ? 'bg-brand-accent/20 text-brand-goldink dark:text-brand-accent'
                    : 'bg-black/5 dark:bg-white/10'
                )}>
                  {tab.count}
                </span>
              </button>
            ))}
          </div>

          {/* Search box */}
          <div className="relative min-w-[220px] max-w-sm">
            <input
              type="text"
              placeholder={t('reviews.searchPlaceholder') || 'Rechercher dans les segments...'}
              value={searchQuery}
              onChange={(e) => setSearchQuery(e.target.value)}
              className="w-full text-xs px-3 py-2 pl-8 rounded-xl bg-white dark:bg-[#141414] border border-black/10 dark:border-white/10 text-brand-dark dark:text-white placeholder:text-brand-dark/30 dark:placeholder:text-white/30 outline-none focus:border-brand-accent/60"
            />
            <Search size={14} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-brand-dark/40 dark:text-white/40 pointer-events-none" />
          </div>
        </div>
      )}

      {isLoading ? (
        <div className="flex items-center justify-center py-16">
          <Loader2 className="size-6 animate-spin text-muted-foreground" />
        </div>
      ) : segments.length === 0 && !loadError ? (
        <div className="rounded-xl border border-black/10 dark:border-white/10 bg-white dark:bg-[#141414] px-6 py-14 text-center shadow-sm">
          <p className="text-sm font-semibold text-brand-dark dark:text-white">
            {t('reviews.empty.title')}
          </p>
          <p className="mx-auto mt-2 max-w-md text-xs leading-relaxed text-brand-dark/60 dark:text-white/60">
            {t('reviews.empty.desc')}
          </p>
        </div>
      ) : (
        <div className="overflow-hidden rounded-xl border border-black/10 dark:border-white/10 bg-white dark:bg-[#141414] shadow-sm">
          <table className="w-full text-sm">
            <thead className="bg-brand-muted/40 dark:bg-white/5 text-left text-xs uppercase tracking-wider text-brand-dark/50 dark:text-white/50 border-b border-black/5 dark:border-white/5">
              <tr>
                <th className="w-1/2 px-4 py-3 font-semibold">{t('reviews.col.source')}</th>
                <th className="w-1/2 px-4 py-3 font-semibold">{t('reviews.col.target')}</th>
                <th className="w-40 px-4 py-3 font-semibold">{t('reviews.col.status')}</th>
              </tr>
            </thead>
            <tbody>
              {filteredSegments.length === 0 ? (
                <tr>
                  <td colSpan={3} className="px-4 py-12 text-center text-xs text-brand-dark/40 dark:text-white/40 italic">
                    {t('reviews.noMatchingSegments') || 'Aucun segment ne correspond à votre filtre.'}
                  </td>
                </tr>
              ) : (
                filteredSegments.map((seg) => {
                  const isEditing = editingId === seg.id;
                  const finalText = seg.status === 'edited' && seg.reviewed_text
                    ? seg.reviewed_text
                    : seg.translated_text;
                  return (
                    <tr key={seg.id} className="border-t border-black/5 dark:border-white/5 align-top hover:bg-brand-muted/20 dark:hover:bg-white/[0.02] transition-colors">
                      <td className="px-4 py-3 text-brand-dark/70 dark:text-white/70 leading-relaxed">
                        {seg.source_text}
                      </td>
                      <td className="px-4 py-3">
                        {isEditing ? (
                          <div className="space-y-2">
                            <textarea
                              className="min-h-20 w-full rounded-lg border border-black/10 dark:border-white/10 bg-brand-muted/20 dark:bg-black/20 px-3 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-brand-accent/40 text-sm leading-relaxed"
                              value={draft}
                              onChange={(e) => setDraft(e.target.value)}
                              onKeyDown={(e) => {
                                if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
                                  e.preventDefault();
                                  if (draft.trim() && savingId !== seg.id) {
                                    patchSegment(seg.id, {
                                      reviewed_text: draft,
                                      status: 'edited',
                                    });
                                    setEditingId(null);
                                  }
                                }
                              }}
                            />
                            <div className="flex items-center justify-between">
                              <div className="flex gap-2">
                                <Button
                                  size="sm"
                                  disabled={savingId === seg.id || !draft.trim()}
                                  onClick={async () => {
                                    await patchSegment(seg.id, {
                                      reviewed_text: draft,
                                      status: 'edited',
                                    });
                                    setEditingId(null);
                                  }}
                                >
                                  {savingId === seg.id ? (
                                    <Loader2 className="size-3.5 animate-spin" />
                                  ) : (
                                    <Check className="size-3.5" />
                                  )}
                                  {t('reviews.save')}
                                </Button>
                                <Button
                                  size="sm"
                                  variant="ghost"
                                  onClick={() => setEditingId(null)}
                                >
                                  {t('reviews.cancel')}
                                </Button>
                              </div>
                              <span className="text-[10px] text-brand-dark/40 dark:text-white/40 italic hidden sm:inline">
                                {t('reviews.shortcutHint') || 'Ctrl + Entrée pour enregistrer'}
                              </span>
                            </div>
                          </div>
                        ) : (
                          <div
                            className={cn(
                              'whitespace-pre-wrap leading-relaxed',
                              seg.status === 'edited' ? 'text-blue-600 dark:text-blue-400 font-medium' : 'text-brand-dark dark:text-white'
                            )}
                          >
                            {finalText || <span className="italic text-muted-foreground">{t('reviews.emptyCell')}</span>}
                          </div>
                        )}
                      </td>
                      <td className="px-4 py-3">
                        <div className="flex flex-col items-start gap-2">
                          {statusBadge(seg.status)}
                          {!isEditing && (
                            <div className="flex flex-wrap gap-1">
                              <Button
                                size="sm"
                                variant="ghost"
                                className="h-7 gap-1 px-2 text-[11px]"
                                onClick={() => {
                                  setEditingId(seg.id);
                                  setDraft(finalText);
                                }}
                              >
                                <Pencil className="size-3" /> {t('reviews.action.edit')}
                              </Button>
                              <Button
                                size="sm"
                                variant="ghost"
                                className="h-7 gap-1 px-2 text-[11px]"
                                disabled={seg.status === 'approved' || savingId === seg.id}
                                onClick={() => patchSegment(seg.id, { status: 'approved' })}
                              >
                                <Check className="size-3" /> {t('reviews.action.approveShort')}
                              </Button>
                              <Button
                                size="sm"
                                variant="ghost"
                                className="h-7 gap-1 px-2 text-[11px]"
                                disabled={seg.status === 'pending'}
                                onClick={() => patchSegment(seg.id, { status: 'pending' })}
                              >
                                <Undo2 className="size-3" /> {t('reviews.action.resetShort')}
                              </Button>
                            </div>
                          )}
                        </div>
                      </td>
                    </tr>
                  );
                })
              )}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}
