'use client';

import React, { useState, useRef, useEffect, useCallback } from 'react';
import { motion } from 'framer-motion';
import { X, FlipHorizontal, RefreshCw, ArrowRight } from 'lucide-react';
import { AuraScanAnimation, AURA_SCAN_MIN_MS } from './AuraScanAnimation';
import { AuraQuestionnaire } from './AuraQuestionnaire';
import { AuraPhoto, AuraZoneLegend } from '@/components/insights/AuraPhoto';
import { readAuraField } from '@/lib/aura/auraField';
import { CHAKRA_LEVELS, CHAKRA_PLAIN, chakraLevel } from '@/lib/aura/chakraGuide';
import { FaceAuraAnalysisResult } from '@/lib/aura/faceAnalyzer';
import { chakraMeta } from '@/lib/aura/chakraMeta';
import { useLocale, useMessages } from '@/i18n/client';
import { ChakraType } from '@/lib/aura/types';

const revealItem = {
  hidden: { opacity: 0, y: 16 },
  show: { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] as const } },
};

interface LiveDeviceCameraProps {
  isOpen: boolean;
  onClose: () => void;
  onSuccess?: (result: FaceAuraAnalysisResult, photo: string) => void;
  /** Called from the result screen — navigates to the full report. */
  onViewReport?: () => void;
  /** Replaces the default result actions (used by the session kiosk). */
  renderActions?: () => React.ReactNode;
}

export const LiveDeviceCamera: React.FC<LiveDeviceCameraProps> = ({
  isOpen,
  onClose,
  onSuccess,
  onViewReport,
  renderActions,
}) => {
  const locale = useLocale();
  const t = useMessages().camera;
  // The 35 answers that set the aura colours; the camera opens once they're in.
  const [answers, setAnswers] = useState<Record<string, number> | null>(null);
  const [facingMode, setFacingMode] = useState<'user' | 'environment'>('user');
  const [streamReady, setStreamReady] = useState(false);
  const [cameraError, setCameraError] = useState<string | null>(null);
  const [capturedImage, setCapturedImage] = useState<string | null>(null);
  const [analyzing, setAnalyzing] = useState(false);
  const [analysisResult, setAnalysisResult] = useState<FaceAuraAnalysisResult | null>(null);
  const [analyzeError, setAnalyzeError] = useState<string | null>(null);
  // Incremented per shutter press so the flash overlay re-mounts and replays.
  const [flashKey, setFlashKey] = useState(0);

  const videoRef = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const streamRef = useRef<MediaStream | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  // Bumped on every start/stop so an in-flight getUserMedia/play() from a
  // superseded call (e.g. Strict Mode's double effect) is discarded.
  const requestIdRef = useRef(0);

  const startStream = useCallback(async (facing: 'user' | 'environment') => {
    const requestId = ++requestIdRef.current;
    setCameraError(null);
    setStreamReady(false);
    try {
      if (streamRef.current) {
        streamRef.current.getTracks().forEach((t) => t.stop());
        streamRef.current = null;
      }

      const stream = await navigator.mediaDevices.getUserMedia({
        video: {
          facingMode: facing,
          width: { ideal: 1280 },
          height: { ideal: 720 },
        },
        audio: false,
      });

      if (requestId !== requestIdRef.current) {
        stream.getTracks().forEach((t) => t.stop());
        return;
      }

      streamRef.current = stream;
      if (videoRef.current) {
        videoRef.current.srcObject = stream;
        await videoRef.current.play();
        if (requestId === requestIdRef.current) setStreamReady(true);
      }
    } catch (err: unknown) {
      if (requestId !== requestIdRef.current) return;
      if (err instanceof DOMException && err.name === 'AbortError') return;
      console.warn('Camera error:', err);
      setCameraError(t.cameraError);
      setStreamReady(false);
    }
  }, []);

  const stopStream = useCallback(() => {
    requestIdRef.current++;
    if (streamRef.current) {
      streamRef.current.getTracks().forEach((t) => t.stop());
      streamRef.current = null;
    }
    setStreamReady(false);
  }, []);

  useEffect(() => {
    if (isOpen && answers && !capturedImage && !analysisResult) {
      startStream(facingMode);
    }
    return () => {
      stopStream();
    };
  }, [isOpen, answers, capturedImage, analysisResult, facingMode, startStream, stopStream]);

  const handleCapture = () => {
    if (!videoRef.current || !canvasRef.current) return;
    const video = videoRef.current;
    const canvas = canvasRef.current;

    canvas.width = video.videoWidth || 720;
    canvas.height = video.videoHeight || 960;

    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    if (facingMode === 'user') {
      ctx.translate(canvas.width, 0);
      ctx.scale(-1, 1);
    }
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

    const dataUrl = canvas.toDataURL('image/jpeg', 0.9);
    setFlashKey((k) => k + 1);
    setCapturedImage(dataUrl);
    stopStream();
    processFaceAura(dataUrl);
  };

  const handleUploadFallback = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      const reader = new FileReader();
      reader.onloadend = () => {
        const url = reader.result as string;
        setCapturedImage(url);
        stopStream();
        processFaceAura(url);
      };
      reader.readAsDataURL(file);
    }
  };

  const processFaceAura = async (photo: string) => {
    setAnalyzing(true);
    setAnalyzeError(null);
    try {
      // Let the scan sequence play out even when the API answers instantly.
      const [res] = await Promise.all([
        fetch('/api/aura/analyze-face', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ answers }),
        }),
        new Promise((resolve) => setTimeout(resolve, AURA_SCAN_MIN_MS)),
      ]);
      const data = await res.json();
      if (data.success && data.data) {
        setAnalysisResult(data.data);
        onSuccess?.(data.data, photo);
      } else {
        setAnalyzeError(t.analyzeFailed);
      }
    } catch (e) {
      console.error(e);
      setAnalyzeError(t.connectionLost);
    } finally {
      setAnalyzing(false);
    }
  };

  const resetCapture = () => {
    setCapturedImage(null);
    setAnalysisResult(null);
    setAnalyzeError(null);
    setAnalyzing(false);
    // The effect restarts the stream once capturedImage/analysisResult clear.
  };

  const flipCamera = () => {
    // The effect restarts the stream when facingMode changes.
    setFacingMode((prev) => (prev === 'user' ? 'environment' : 'user'));
  };

  if (!isOpen) return null;

  const chakras: ChakraType[] = [
    'crown',
    'third_eye',
    'throat',
    'heart',
    'solar_plexus',
    'sacral',
    'root',
  ];

  return (
    <div className="fixed inset-0 z-50 flex items-start justify-center bg-black/95 backdrop-blur-2xl p-4 sm:p-6 overflow-y-auto">
      <div className="relative w-full max-w-2xl bg-[#090A0F] border border-white/10 rounded-[32px] overflow-hidden shadow-2xl flex flex-col my-auto">
        {/* Shutter flash */}
        {flashKey > 0 && (
          <motion.div
            key={flashKey}
            aria-hidden
            className="pointer-events-none absolute inset-0 z-30 bg-white"
            initial={{ opacity: 0.95 }}
            animate={{ opacity: 0 }}
            transition={{ duration: 0.7, ease: 'easeOut' }}
          />
        )}

        {/* Top Header */}
        <div className="px-6 py-4 flex items-center justify-between border-b border-white/[0.08]">
          <span className="text-xs font-semibold uppercase tracking-widest text-[#86868B]">
            {!answers ? t.step1 : !analysisResult ? t.step2 : t.result}
          </span>
          <button
            onClick={() => {
              stopStream();
              onClose();
            }}
            className="w-8 h-8 rounded-full bg-white/10 hover:bg-white/20 text-white flex items-center justify-center transition-colors"
          >
            <X className="w-4 h-4" />
          </button>
        </div>

        {/* 0. Questionnaire — its answers colour the aura */}
        {!answers && <AuraQuestionnaire onComplete={setAnswers} />}

        {/* 1. Live Camera Viewfinder */}
        {answers && !capturedImage && !analysisResult && (
          <div className="p-6 sm:p-8 flex flex-col items-center">
            <div className="relative w-full aspect-[3/4] max-w-sm rounded-[28px] overflow-hidden bg-black flex items-center justify-center border border-white/10 shadow-2xl">
              <video
                ref={videoRef}
                autoPlay
                playsInline
                muted
                className={`w-full h-full object-cover ${
                  facingMode === 'user' ? 'scale-x-[-1]' : ''
                }`}
              />

              {/* Minimal framing guides */}
              <div className="absolute inset-8 pointer-events-none border border-white/20 rounded-2xl flex flex-col justify-between p-4">
                <div className="flex justify-between">
                  <div className="w-4 h-4 border-t-2 border-l-2 border-white/80 rounded-tl" />
                  <div className="w-4 h-4 border-t-2 border-r-2 border-white/80 rounded-tr" />
                </div>
                <div className="flex justify-between">
                  <div className="w-4 h-4 border-b-2 border-l-2 border-white/80 rounded-bl" />
                  <div className="w-4 h-4 border-b-2 border-r-2 border-white/80 rounded-br" />
                </div>
              </div>

              {cameraError && (
                <div className="absolute inset-0 bg-black/90 p-6 flex flex-col items-center justify-center text-center space-y-4">
                  <p className="text-xs text-slate-300 max-w-xs">{cameraError}</p>
                  <button
                    onClick={() => fileInputRef.current?.click()}
                    className="px-5 py-2.5 rounded-full bg-white text-black text-xs font-semibold hover:bg-slate-200 transition-colors"
                  >
                    {t.upload}
                  </button>
                </div>
              )}
            </div>

            <canvas ref={canvasRef} className="hidden" />
            <input
              ref={fileInputRef}
              type="file"
              accept="image/*"
              onChange={handleUploadFallback}
              className="hidden"
            />

            {/* Shutter Bar */}
            <div className="w-full max-w-sm mt-6 flex items-center justify-between px-4">
              <button
                onClick={() => fileInputRef.current?.click()}
                className="text-xs text-[#86868B] hover:text-white transition-colors"
              >
                {t.pickFile}
              </button>

              {/* Apple Camera Shutter Ring */}
              <motion.button
                disabled={!streamReady && !cameraError}
                onClick={handleCapture}
                whileHover={{ scale: 1.05 }}
                whileTap={{ scale: 0.88 }}
                className="w-18 h-18 rounded-full border-[3px] border-white p-1 flex items-center justify-center disabled:opacity-40"
              >
                <div className="w-full h-full rounded-full bg-white" />
              </motion.button>

              <button
                onClick={flipCamera}
                title={t.flip}
                aria-label={t.flip}
                className="w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 text-white flex items-center justify-center transition-colors"
              >
                <FlipHorizontal className="w-4 h-4" />
              </button>
            </div>
          </div>
        )}

        {/* 2. Processing State */}
        {analyzing && capturedImage && <AuraScanAnimation photo={capturedImage} />}

        {/* 2b. Analysis failed */}
        {!analyzing && analyzeError && (
          <div className="p-12 flex flex-col items-center text-center space-y-5">
            <p className="text-sm text-slate-300 max-w-xs">{analyzeError}</p>
            <button
              type="button"
              onClick={resetCapture}
              className="inline-flex items-center gap-2 px-5 py-2.5 rounded-full bg-white text-black text-xs font-semibold hover:bg-slate-200 transition-colors"
            >
              <RefreshCw className="w-3.5 h-3.5" />
              {t.retake}
            </button>
          </div>
        )}

        {/* 3. Result State */}
        {!analyzing && analysisResult && capturedImage && (
          <motion.div
            className="p-6 sm:p-8 space-y-8 overflow-y-auto max-h-[80vh]"
            initial="hidden"
            animate="show"
            variants={{ show: { transition: { staggerChildren: 0.12 } } }}
          >
            <motion.div
              variants={revealItem}
              className="flex flex-col sm:flex-row items-center gap-6 pb-6 border-b border-white/[0.08]"
            >
              <motion.div
                className="relative w-24 h-24 shrink-0"
                initial={{ scale: 0.6, opacity: 0 }}
                animate={{ scale: 1, opacity: 1 }}
                transition={{ type: 'spring', stiffness: 220, damping: 16 }}
              >
                {/* Glow in the person's dominant/secondary chakra colours */}
                <motion.div
                  aria-hidden
                  className="absolute -inset-2 rounded-full blur-lg"
                  style={{
                    background: `conic-gradient(${chakraMeta(locale)[analysisResult.dominantChakra].color}, ${chakraMeta(locale)[analysisResult.secondaryChakra].color}, ${chakraMeta(locale)[analysisResult.dominantChakra].color})`,
                  }}
                  animate={{ rotate: 360, opacity: [0.6, 1, 0.6] }}
                  transition={{
                    rotate: { duration: 6, repeat: Infinity, ease: 'linear' },
                    opacity: { duration: 3, repeat: Infinity, ease: 'easeInOut' },
                  }}
                />
                <div className="relative size-full rounded-full overflow-hidden border-2 border-white/40">
                  <img
                    src={capturedImage}
                    alt={t.portrait}
                    className="w-full h-full object-cover"
                  />
                </div>
              </motion.div>

              <div className="text-center sm:text-left space-y-1 flex-1">
                <span className="text-[10px] uppercase tracking-widest text-[#86868B] font-semibold">
                  {t.profileEyebrow}
                </span>
                <h3 className="text-2xl sm:text-3xl font-bold tracking-tight text-white">
                  {chakraMeta(locale)[analysisResult.dominantChakra].archetype}
                </h3>
                <p className="text-xs text-slate-300 leading-relaxed">
                  {analysisResult.interpretation.summary}
                </p>
              </div>
            </motion.div>

            {/* Aura photo with the five-zone reading */}
            {(() => {
              const zones = readAuraField(
                analysisResult.scores,
                { dominant: analysisResult.dominantChakra, secondary: analysisResult.secondaryChakra },
                locale,
              );
              return (
            <motion.div variants={revealItem} className="grid items-center gap-6 sm:grid-cols-2">
              <AuraPhoto photo={capturedImage} zones={zones} className="mx-auto w-full max-w-[280px]" />
              <AuraZoneLegend zones={zones} tone="dark" />
            </motion.div>
              );
            })()}

            {/* Kiosk: the QR is the point of this screen, so it comes first. */}
            {renderActions && <motion.div variants={revealItem}>{renderActions()}</motion.div>}

            {/* 7 Chakras */}
            <motion.div variants={revealItem} className="space-y-3">
              <div>
                <span className="text-[11px] font-semibold uppercase tracking-wider text-[#86868B] block">
                  {t.balanceTitle}
                </span>
                <p className="mt-1 text-xs leading-relaxed text-slate-400">{t.balanceText}</p>
              </div>
              <div className="space-y-2">
                {chakras.map((chKey, i) => {
                  const meta = chakraMeta(locale)[chKey];
                  const score = analysisResult.scores[chKey];
                  return (
                    <div key={chKey} className="space-y-1">
                      <div className="flex justify-between items-center text-xs text-slate-300">
                        <span>
                          {meta.name}{' '}
                          <span className="text-slate-500">· {CHAKRA_PLAIN[locale][chKey].split(/[,，、]/)[0].replace(/[.。]$/, '')}</span>
                        </span>
                        <span className="font-mono text-slate-400">
                          {score}% <span className="font-sans text-[10px] text-slate-500">{CHAKRA_LEVELS[locale][chakraLevel(score)].label}</span>
                        </span>
                      </div>
                      <div className="h-1.5 w-full bg-white/10 rounded-full overflow-hidden">
                        <motion.div
                          className="h-full rounded-full"
                          style={{
                            backgroundColor: meta.color,
                            boxShadow: `0 0 8px ${meta.color}`,
                          }}
                          initial={{ width: 0 }}
                          animate={{ width: `${score}%` }}
                          transition={{ delay: 0.4 + i * 0.08, duration: 0.9, ease: [0.16, 1, 0.3, 1] }}
                        />
                      </div>
                    </div>
                  );
                })}
              </div>
            </motion.div>

            {/* Observations */}
            <motion.div variants={revealItem} className="grid grid-cols-1 sm:grid-cols-2 gap-4">
              <div className="p-4 rounded-2xl bg-white/[0.04] border border-white/5 space-y-1">
                <span className="text-[10px] font-semibold uppercase text-[#86868B]">
                  {t.focus}
                </span>
                <p className="text-xs text-slate-300">
                  {analysisResult.facialObservations.eyeClarity}
                </p>
              </div>
              <div className="p-4 rounded-2xl bg-white/[0.04] border border-white/5 space-y-1">
                <span className="text-[10px] font-semibold uppercase text-[#86868B]">
                  {t.vitality}
                </span>
                <p className="text-xs text-slate-300">
                  {analysisResult.facialObservations.vitalityTone}
                </p>
              </div>
            </motion.div>

            {/* Actions (default) — the scan unlocks the full report, so that is the one next step */}
            {!renderActions && (
            <motion.div variants={revealItem} className="rounded-2xl bg-white/[0.04] p-5 ring-1 ring-white/10 sm:flex sm:items-center sm:justify-between sm:gap-6">
              <div>
                <p className="text-sm font-semibold text-white">{t.reportReady}</p>
                <p className="mt-1 text-xs leading-relaxed text-slate-400">
                  {t.reportChapters}
                </p>
              </div>
              <button
                type="button"
                onClick={() => {
                  stopStream();
                  onViewReport?.();
                }}
                className="group mt-4 inline-flex h-11 w-full shrink-0 items-center justify-center gap-2 rounded-full bg-white px-6 text-sm font-semibold text-black transition-colors hover:bg-slate-200 sm:mt-0 sm:w-auto"
              >
                {t.viewReport}
                <ArrowRight className="size-4 transition-transform group-hover:translate-x-0.5" />
              </button>
            </motion.div>
            )}

            {/* Kiosk results are saved immediately, so a retake there would duplicate the participant. */}
            {!renderActions && (
            <button
              type="button"
              onClick={resetCapture}
              className="mx-auto flex items-center gap-2 text-xs font-semibold text-[#86868B] transition-colors hover:text-white"
            >
              <RefreshCw className="w-3.5 h-3.5" />
              <span>Ambil Foto Ulang</span>
            </button>
            )}
          </motion.div>
        )}
      </div>
    </div>
  );
};
