'use client';

import { useEffect, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import { Camera, Check, Compass, Hash, Sparkles, type LucideIcon } from 'lucide-react';
import { Dialog } from '@/components/ui/Dialog';
import { Button } from '@/components/ui/Button';
import { LiveDeviceCamera } from '@/components/camera/LiveDeviceCamera';
import { BaziAssessmentModal } from '@/components/assessments/BaziAssessmentModal';
import { NumerologyAssessmentModal } from '@/components/assessments/NumerologyAssessmentModal';
import { createReport } from '@/app/actions/reports';
import { downscaleImage } from '@/lib/image';
import { chaptersFor } from '@/components/report/chapters';
import { SERVICES, type Service } from '@/lib/reports/services';
import type { BaziCalculationResult } from '@/lib/bazi/types';
import type { NumerologyCalculationResult } from '@/lib/numerology/types';
import { useMessages } from '@/i18n/client';
import { cn } from '@/lib/cn';

const ICON: Record<Service, LucideIcon> = { aura: Camera, bazi: Compass, numerology: Hash };
// Forms first, camera last — the camera's result screen ends with "view report".
const RUN_ORDER: Service[] = ['bazi', 'numerology', 'aura'];

type Step = 'pick' | Service | 'saving';

/**
 * New report: pick any of the three services (or the bundle), fill in each one,
 * then save everything as a single report.
 */
export function ServiceFlow({
  open,
  onClose,
  preset = [...SERVICES],
  skipPicker = false,
  signedIn = true,
  userName,
  signUpHref = '/daftar',
}: {
  open: boolean;
  onClose: () => void;
  preset?: Service[];
  /** Go straight to the first service (e.g. a "new aura photo" link). */
  skipPicker?: boolean;
  signedIn?: boolean;
  userName?: string;
  signUpHref?: string;
}) {
  const router = useRouter();
  const sv = useMessages().services;
  const [chosen, setChosen] = useState<Service[]>(preset);
  const [step, setStep] = useState<Step | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [cameraKey, setCameraKey] = useState(0);
  // Carried from the BaZi form into the numerology form.
  const [birthDate, setBirthDate] = useState('');
  const data = useRef<{
    bazi?: BaziCalculationResult;
    numerology?: NumerologyCalculationResult;
    scan?: { result: unknown; photo: Promise<string> };
  }>({});

  const queue = RUN_ORDER.filter((s) => chosen.includes(s));
  const presetKey = preset.join(',');

  // Fresh state on every opening.
  useEffect(() => {
    if (!open) {
      // eslint-disable-next-line react-hooks/set-state-in-effect -- reset when closed
      setStep(null);
      return;
    }
    const initial = presetKey.split(',') as Service[];
    setChosen(initial);
    setError(null);
    data.current = {};
    setBirthDate('');
    setCameraKey((n) => n + 1);
    setStep(skipPicker ? RUN_ORDER.filter((s) => initial.includes(s))[0] : 'pick');
  }, [open, presetKey, skipPicker]);

  const close = () => {
    setStep(null);
    onClose();
  };

  const finish = async () => {
    setStep('saving');
    const d = data.current;
    const res = await createReport({
      services: chosen,
      result: d.scan?.result,
      photo: d.scan ? await d.scan.photo : null,
      bazi: d.bazi,
      numerology: d.numerology,
    });
    if (res.ok) {
      close();
      router.push(`/laporan/${res.data.id}`);
    } else {
      setError(res.error);
      setStep(queue[queue.length - 1]);
    }
  };

  const next = (from: Service) => {
    const i = queue.indexOf(from);
    if (i < queue.length - 1) setStep(queue[i + 1]);
    else void finish();
  };

  const start = () => {
    if (!chosen.length) return;
    if (!signedIn) {
      router.push(signUpHref);
      return;
    }
    setStep(queue[0]);
  };

  const toggle = (s: Service) =>
    setChosen((list) => (list.includes(s) ? list.filter((x) => x !== s) : SERVICES.filter((x) => x === s || list.includes(x))));
  const allChosen = chosen.length === SERVICES.length;
  const stepNo = step && step !== 'pick' && step !== 'saving' ? queue.indexOf(step) + 1 : 0;

  return (
    <>
      <Dialog open={open && step === 'pick'} onClose={close} title={sv.picker.title} description={sv.picker.description}>
        <p className="-mt-2 mb-5 inline-flex items-center gap-1.5 rounded-full bg-wood/10 px-3 py-1 text-xs font-semibold text-wood">
          <Sparkles className="size-3.5" aria-hidden />
          {sv.picker.trial}
        </p>

        <button
          type="button"
          onClick={() => setChosen(allChosen ? [] : [...SERVICES])}
          aria-pressed={allChosen}
          className={cn(
            'flex w-full items-center gap-4 rounded-card p-4 text-left transition-colors',
            allChosen ? 'bg-night-900 text-white' : 'bg-canvas text-ink ring-1 ring-line hover:bg-surface',
          )}
        >
          <span className="flex -space-x-2" aria-hidden>
            {SERVICES.map((s) => {
              const Icon = ICON[s];
              return (
                <span
                  key={s}
                  className={cn(
                    'inline-flex size-9 items-center justify-center rounded-full ring-2',
                    allChosen ? 'bg-white/15 ring-night-900' : 'bg-surface ring-canvas',
                  )}
                >
                  <Icon className="size-4" />
                </span>
              );
            })}
          </span>
          <span className="flex-1">
            <span className="block text-[15px] font-semibold">{sv.picker.bundle}</span>
            <span className={cn('mt-0.5 block text-[13px]', allChosen ? 'text-white/65' : 'text-muted')}>
              {sv.picker.bundleText}
            </span>
          </span>
          <Tick on={allChosen} dark={allChosen} />
        </button>

        <ul className="mt-3 space-y-2">
          {SERVICES.map((s) => {
            const Icon = ICON[s];
            const on = chosen.includes(s);
            return (
              <li key={s}>
                <button
                  type="button"
                  onClick={() => toggle(s)}
                  aria-pressed={on}
                  className={cn(
                    'flex w-full items-start gap-4 rounded-2xl p-4 text-left ring-1 transition-colors',
                    on ? 'bg-accent-soft/60 ring-accent/40' : 'ring-line hover:bg-canvas',
                  )}
                >
                  <span
                    className={cn(
                      'inline-flex size-10 shrink-0 items-center justify-center rounded-full',
                      on ? 'bg-accent text-white' : 'bg-canvas text-ink-soft ring-1 ring-line',
                    )}
                  >
                    <Icon className="size-[18px]" aria-hidden />
                  </span>
                  <span className="min-w-0 flex-1">
                    <span className="flex flex-wrap items-center gap-2 text-sm font-semibold text-ink">
                      {sv.names[s]}
                      <span className="rounded-full bg-surface px-2 py-0.5 text-[10px] font-medium text-muted ring-1 ring-line">
                        {sv.picker.chapters(chaptersFor([s]).length)}
                      </span>
                    </span>
                    <span className="mt-1 block text-[13px] leading-relaxed text-muted">{sv.picker.items[s]}</span>
                  </span>
                  <Tick on={on} />
                </button>
              </li>
            );
          })}
        </ul>

        <div className="mt-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
          <p className="text-[13px] text-muted">
            {chosen.length ? `${sv.picker.selected(chosen.length)} · ${sv.picker.chapters(chaptersFor(chosen).length)}` : sv.picker.pickOne}
          </p>
          <Button onClick={start} disabled={!chosen.length} withArrow>
            {signedIn ? sv.picker.continue : sv.picker.signUp}
          </Button>
        </div>
      </Dialog>

      <BaziAssessmentModal
        key={`bazi-${cameraKey}`}
        isOpen={open && step === 'bazi'}
        onClose={close}
        initial={{ name: userName }}
        onComplete={(r) => {
          data.current.bazi = r;
          setBirthDate(r.input?.birthDate ?? '');
          next('bazi');
        }}
      />
      <NumerologyAssessmentModal
        isOpen={open && step === 'numerology'}
        onClose={close}
        key={`numerology-${cameraKey}-${birthDate}`}
        initial={{ name: userName, birthDate }}
        onComplete={(r) => {
          data.current.numerology = r;
          next('numerology');
        }}
      />
      <LiveDeviceCamera
        key={cameraKey}
        isOpen={open && (step === 'aura' || (step === 'saving' && chosen.includes('aura')))}
        onClose={close}
        onSuccess={(result, photo) => {
          data.current.scan = { result, photo: downscaleImage(photo) };
        }}
        onViewReport={() => {
          if (data.current.scan && step === 'aura') next('aura');
        }}
      />

      {open && stepNo > 0 && queue.length > 1 && (
        <p className="pointer-events-none fixed inset-x-0 top-3 z-[60] mx-auto w-fit rounded-full bg-white/95 px-4 py-1.5 text-xs font-semibold text-ink shadow-float">
          {sv.picker.steps(stepNo, queue.length)} · {sv.names[step as Service]}
        </p>
      )}
      {open && step === 'saving' && (
        <p
          role="status"
          className="fixed inset-x-4 top-4 z-[70] mx-auto max-w-xs rounded-full bg-white px-4 py-2.5 text-center text-sm font-medium text-ink shadow-float"
        >
          {sv.picker.saving}
        </p>
      )}
      {open && error && (
        <p
          role="alert"
          className="fixed inset-x-4 top-14 z-[70] mx-auto max-w-md rounded-2xl bg-fire px-4 py-3 text-center text-sm font-medium text-white shadow-float"
        >
          {error}
        </p>
      )}
    </>
  );
}

function Tick({ on, dark = false }: { on: boolean; dark?: boolean }) {
  return (
    <span
      aria-hidden
      className={cn(
        'mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-md ring-1 transition-colors',
        on ? (dark ? 'bg-white text-night-900 ring-white' : 'bg-accent text-white ring-accent') : 'ring-line-strong',
      )}
    >
      {on && <Check className="size-3.5" strokeWidth={3} />}
    </span>
  );
}
