'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useParams } from 'next/navigation';
import {
  Check,
  CheckCheck,
  Download,
  FileDown,
  FileUp,
  Loader2,
  Pencil,
  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 { PageHeader } from '@/components/layout/page-header';
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 [isImporting, setIsImporting] = useState(false);
  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(err instanceof Error ? err.message : t('reviews.error.load'));
    } finally {
      setIsLoading(false);
    }
  }, [jobId]);

  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 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');
    for (const seg of pending) {
      // sequential is fine — server-side each is a tiny PATCH
      await patchSegment(seg.id, { status: 'approved' });
    }
    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-3">
        <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">
            {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}>
            <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}>
            {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>
      )}

      {isLoading ? (
        <div className="flex items-center justify-center py-16">
          <Loader2 className="size-6 animate-spin text-muted-foreground" />
        </div>
      ) : (
        <div className="overflow-hidden rounded-lg border border-border">
          <table className="w-full text-sm">
            <thead className="bg-muted/50 text-left text-xs uppercase tracking-wide text-muted-foreground">
              <tr>
                <th className="w-1/2 px-4 py-2.5 font-medium">{t('reviews.col.source')}</th>
                <th className="w-1/2 px-4 py-2.5 font-medium">{t('reviews.col.target')}</th>
                <th className="w-40 px-4 py-2.5 font-medium">{t('reviews.col.status')}</th>
              </tr>
            </thead>
            <tbody>
              {segments.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-border align-top">
                    <td className="px-4 py-3 text-muted-foreground">
                      {seg.source_text}
                    </td>
                    <td className="px-4 py-3">
                      {isEditing ? (
                        <div className="space-y-2">
                          <textarea
                            className="min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-ring"
                            value={draft}
                            onChange={(e) => setDraft(e.target.value)}
                          />
                          <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>
                        </div>
                      ) : (
                        <div
                          className={cn(
                            'whitespace-pre-wrap',
                            seg.status === 'edited' && 'text-blue-600 dark:text-blue-400'
                          )}
                        >
                          {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>
  );
}
