'use client';

import { useState, useEffect, useRef } from 'react';
import Link from 'next/link';
import { ArrowLeft, ClipboardCheck, MapPin, CheckCircle2, Loader2, AlertTriangle } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { trpc } from '@/lib/trpc/client';
import type { RouterOutputs } from '@/lib/trpc/server';

type Defect = RouterOutputs['qualityDefect']['forMyStation'][number];
type DefectStatus = 'OPEN' | 'ACKNOWLEDGED' | 'CORRECTED';
type TFn = (key: string, values?: Record<string, string | number>) => string;

function timeAgo(date: Date | string, t: TFn): string {
  const diffMs = Date.now() - new Date(date).getTime();
  const mins = Math.floor(diffMs / 60_000);
  if (mins < 1) return t('now');
  if (mins < 60) return t('minutesAgo', { mins });
  const hours = Math.floor(mins / 60);
  if (hours < 24) return t('hoursAgo', { hours });
  return t('daysAgo', { days: Math.floor(hours / 24) });
}

function playBeep() {
  try {
    const ctx = new AudioContext();
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.connect(gain);
    gain.connect(ctx.destination);
    osc.type = 'sine';
    osc.frequency.value = 880;
    gain.gain.setValueAtTime(0.2, ctx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.4);
    osc.start(ctx.currentTime);
    osc.stop(ctx.currentTime + 0.4);
  } catch {
    // AudioContext may be blocked before user interaction — ignore.
  }
}

const STATUS_CLASS: Record<DefectStatus, string> = {
  OPEN: 'bg-orange-100 text-orange-700',
  ACKNOWLEDGED: 'bg-blue-100 text-blue-700',
  CORRECTED: 'bg-green-100 text-green-700',
};

function Thumbnail({ photoKey, alt }: { photoKey: string | null; alt: string }) {
  const { data } = trpc.storage.signPhotoDownload.useQuery(
    { photoKey: photoKey! },
    { enabled: !!photoKey, staleTime: 50_000 },
  );
  if (!photoKey) return null;
  if (!data?.url) {
    return <div className="h-20 w-20 shrink-0 animate-pulse rounded-lg bg-muted" />;
  }
  return (
    // eslint-disable-next-line @next/next/no-img-element
    <img src={data.url} alt={alt} className="h-20 w-20 shrink-0 rounded-lg object-cover" />
  );
}

function CorrectDialog({
  onConfirm,
  onCancel,
  note,
  onNoteChange,
  busy,
  t,
  tc,
}: {
  onConfirm: () => void;
  onCancel: () => void;
  note: string;
  onNoteChange: (v: string) => void;
  busy: boolean;
  t: ReturnType<typeof useTranslations<'quality'>>;
  tc: ReturnType<typeof useTranslations<'common'>>;
}) {
  return (
    <div className="fixed inset-0 z-50 flex items-end justify-center bg-black/40 p-4 sm:items-center">
      <div className="w-full max-w-md rounded-2xl bg-card p-6 shadow-xl">
        <h2 className="mb-4 text-lg font-semibold">{t('correctDialogTitle')}</h2>
        <label className="mb-1 block text-sm font-medium">{t('correctNoteLabel')}</label>
        <textarea
          value={note}
          onChange={(e) => onNoteChange(e.target.value)}
          rows={3}
          placeholder={t('correctNotePlaceholder')}
          className="mb-4 w-full resize-none rounded-lg border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
        />
        <div className="flex justify-end gap-3">
          <button onClick={onCancel} className="rounded-lg px-4 py-2 text-sm hover:bg-accent">
            {tc('cancel')}
          </button>
          <button
            onClick={onConfirm}
            disabled={busy}
            className="flex items-center gap-1.5 rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white hover:opacity-90 disabled:opacity-50"
          >
            {busy && <Loader2 className="h-4 w-4 animate-spin" />}
            {tc('confirm')}
          </button>
        </div>
      </div>
    </div>
  );
}

function DefectCard({
  defect,
  onAcknowledge,
  onCorrect,
  acknowledging,
  t,
  tc,
}: {
  defect: Defect;
  onAcknowledge: () => void;
  onCorrect: () => void;
  acknowledging: boolean;
  t: ReturnType<typeof useTranslations<'quality'>>;
  tc: ReturnType<typeof useTranslations<'common'>>;
}) {
  const status = defect.status as DefectStatus;
  return (
    <div className="flex flex-col gap-3 rounded-xl border border-border bg-card p-4 shadow-sm">
      <div className="flex gap-3">
        <Thumbnail photoKey={defect.photoKey} alt={t('photo')} />
        <div className="min-w-0 flex-1">
          <div className="flex items-start justify-between gap-2">
            <p className="font-semibold">{defect.defectType}</p>
            <span className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium ${STATUS_CLASS[status]}`}>
              {t(`status.${status.toLowerCase() as 'open' | 'acknowledged' | 'corrected'}`)}
            </span>
          </div>
          {defect.location && (
            <p className="mt-0.5 text-xs text-muted-foreground">
              {t('location')}: {defect.location}
            </p>
          )}
          <p className="mt-1 text-sm text-muted-foreground">{defect.description}</p>
          <div className="mt-1.5 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
            {defect.rfsCode && (
              <span className="rounded bg-muted px-1.5 py-0.5 font-mono">
                {t('rfs')} {defect.rfsCode}
              </span>
            )}
            <span>{t('raised', { email: defect.createdBy.email, time: timeAgo(defect.createdAt, tc) })}</span>
          </div>
        </div>
      </div>

      <div className="flex items-center justify-end gap-3">
        {status === 'OPEN' && (
          <button
            onClick={onAcknowledge}
            disabled={acknowledging}
            className="flex items-center gap-1.5 rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50"
          >
            {acknowledging ? <Loader2 className="h-4 w-4 animate-spin" /> : <ClipboardCheck className="h-4 w-4" />}
            {t('acknowledge')}
          </button>
        )}
        {status === 'ACKNOWLEDGED' && (
          <>
            {defect.acknowledgedAt && (
              <p className="text-xs text-muted-foreground">
                {t('acknowledgedBy', { time: timeAgo(defect.acknowledgedAt, tc) })}
              </p>
            )}
            <button
              onClick={onCorrect}
              className="flex items-center gap-1.5 rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white hover:opacity-90"
            >
              <CheckCircle2 className="h-4 w-4" />
              {t('correct')}
            </button>
          </>
        )}
      </div>
    </div>
  );
}

export default function QualityDefectsPage() {
  const t = useTranslations('quality');
  const tc = useTranslations('common');
  const tcTime = useTranslations('common.timeAgo');

  const [correctId, setCorrectId] = useState<string | null>(null);
  const [correctionNote, setCorrectionNote] = useState('');
  const [soundEnabled, setSoundEnabled] = useState(false);

  const { data: session } = trpc.operatorSession.current.useQuery();
  const { data: defects = [], refetch } = trpc.qualityDefect.forMyStation.useQuery(undefined, {
    refetchInterval: 5000,
    refetchIntervalInBackground: false,
  });

  const acknowledge = trpc.qualityDefect.acknowledge.useMutation({ onSuccess: () => refetch() });
  const correct = trpc.qualityDefect.correct.useMutation({
    onSuccess: () => {
      setCorrectId(null);
      refetch();
    },
  });

  const openIds = defects.filter((d) => d.status === 'OPEN').map((d) => d.id);

  // Beep when a new OPEN defect arrives.
  const prevOpenIds = useRef(new Set<string>());
  useEffect(() => {
    const current = new Set(openIds);
    const hasNew = [...current].some((id) => !prevOpenIds.current.has(id));
    if (hasNew && prevOpenIds.current.size > 0 && soundEnabled) playBeep();
    prevOpenIds.current = current;
  }, [openIds, soundEnabled]);

  return (
    <main className="mx-auto flex min-h-dvh max-w-lg flex-col bg-background">
      <header className="sticky top-0 z-10 flex items-center gap-3 border-b border-border bg-card px-4 py-3">
        <Link href="/" className="rounded-md p-1 hover:bg-accent" aria-label={t('backHome')}>
          <ArrowLeft className="h-5 w-5" />
        </Link>
        <div className="min-w-0 flex-1">
          <h1 className="text-base font-semibold">{t('title')}</h1>
          {session && (
            <p className="flex items-center gap-1 text-xs text-muted-foreground">
              <MapPin className="h-3 w-3" />
              {t('subtitle', { code: session.workstation.code })}
            </p>
          )}
        </div>
        <button
          onClick={() => setSoundEnabled((v) => !v)}
          className={`rounded-full px-3 py-1 text-xs font-medium transition-colors ${
            soundEnabled ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'
          }`}
        >
          {soundEnabled ? t('soundOn') : t('soundOff')}
        </button>
      </header>

      <div className="flex flex-1 flex-col gap-3 p-4">
        {!session ? (
          <div className="py-16 text-center text-muted-foreground">
            <AlertTriangle className="mx-auto mb-3 h-10 w-10 opacity-30" />
            <p>{t('noSession')}</p>
          </div>
        ) : defects.length === 0 ? (
          <div className="py-16 text-center text-muted-foreground">
            <ClipboardCheck className="mx-auto mb-3 h-10 w-10 opacity-30" />
            <p>{t('empty')}</p>
          </div>
        ) : (
          defects.map((defect) => (
            <DefectCard
              key={defect.id}
              defect={defect}
              t={t}
              tc={tcTime}
              acknowledging={acknowledge.isPending && acknowledge.variables?.id === defect.id}
              onAcknowledge={() => acknowledge.mutate({ id: defect.id })}
              onCorrect={() => {
                setCorrectId(defect.id);
                setCorrectionNote('');
              }}
            />
          ))
        )}
      </div>

      {correctId && (
        <CorrectDialog
          note={correctionNote}
          onNoteChange={setCorrectionNote}
          t={t}
          tc={tc}
          busy={correct.isPending}
          onConfirm={() =>
            correct.mutate({ id: correctId, correctionNote: correctionNote.trim() || undefined })
          }
          onCancel={() => setCorrectId(null)}
        />
      )}
    </main>
  );
}
