"use client";

import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
import Webcam from "react-webcam";
import { useQRScanner } from "@/hooks/useQRScanner";

export type QRScannerProps = {
  onResult?: (text: string) => void;
  onError?: (error: unknown) => void;
  /** When true the camera stops; when it goes back to false the camera auto-resumes if it was on. */
  paused?: boolean;
};

export type QRScannerHandle = {
  /** Hard-stop the scanner (user must press "Scan Ticket" to restart). */
  stop: () => void;
};

// Mobile-friendly QR scanner with start/stop control using the back camera via react-webcam
export const QRScanner = React.forwardRef<QRScannerHandle, QRScannerProps>(
  function QRScanner({ onResult, onError, paused = false }, ref) {
    const webcamRef = useRef<Webcam | null>(null);

    const [localError, setLocalError] = useState<string | null>(null);
    const [showCam, setShowCam] = useState<boolean>(false);

    // Track the underlying HTMLVideoElement from react-webcam reliably
    const [videoEl, setVideoEl] = useState<HTMLVideoElement | null>(null);
    useEffect(() => {
      let id: any;
      if (showCam) {
        id = setInterval(() => {
          const anyCam = webcamRef.current as any;
          const v: HTMLVideoElement | null = anyCam?.video ?? null;
          if (v) { setVideoEl(v); clearInterval(id); }
        }, 100);
      } else {
        setVideoEl(null);
      }
      return () => { if (id) clearInterval(id); };
    }, [showCam]);

    // Beep + cooldown state
    const lastScanRef = useRef<number>(0);
    const audioCtxRef = useRef<any>(null);
    const playBeep = () => {
      try {
        const AC = (window as any).AudioContext || (window as any).webkitAudioContext;
        if (!AC) return;
        if (!audioCtxRef.current) audioCtxRef.current = new AC();
        const ctx = audioCtxRef.current as AudioContext;
        const oscillator = ctx.createOscillator();
        const gainNode = ctx.createGain();
        oscillator.type = "sine";
        oscillator.frequency.value = 880;
        gainNode.gain.value = 0.05;
        oscillator.connect(gainNode);
        gainNode.connect(ctx.destination);
        const now = ctx.currentTime;
        oscillator.start(now);
        oscillator.stop(now + 0.12);
      } catch {}
    };

    const wrappedOnResult = (text: string) => {
      const nowTs = Date.now();
      if (nowTs - lastScanRef.current < 2000) return;
      lastScanRef.current = nowTs;
      playBeep();
      onResult?.(text);
    };

    const { active, toggle, stop, permissionError } = useQRScanner(videoEl, {
      onResult: wrappedOnResult,
      onError,
    });

    const constraints = useMemo(() => ({
      facingMode: { ideal: "environment" },
      width: { ideal: 1280 },
      height: { ideal: 720 },
    }), []);

    const isSecure = typeof window !== "undefined" && window.isSecureContext;
    const isOn = showCam;

    // Stable stop function so effects and the ref handle can depend on it safely
    const stopScan = useCallback(() => {
      try { stop(); } catch {}
      setShowCam(false);
    }, [stop]);

    // Expose hard-stop to parent via ref (used when filters change)
    useImperativeHandle(ref, () => ({ stop: stopScan }), [stopScan]);

    // Pause / auto-resume when the paused prop changes (e.g. a modal opens/closes)
    const wasActiveRef = useRef(false);
    useEffect(() => {
      if (paused) {
        if (showCam) {
          wasActiveRef.current = true;
          stopScan();
        }
      } else {
        if (wasActiveRef.current) {
          wasActiveRef.current = false;
          // Re-show the camera — active is still true so the decode loop restarts automatically
          // once the video element is acquired again.
          setShowCam(true);
        }
      }
    // showCam intentionally included: re-evaluate after stopScan sets it to false
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [paused, stopScan]);

    async function startScan() {
      const host = typeof window !== "undefined" ? window.location.hostname : "";
      const isLocal = host === "localhost" || host === "127.0.0.1";
      if (!(navigator as any)?.mediaDevices?.getUserMedia) {
        setLocalError("Camera API is not available in this browser.");
        return;
      }
      setLocalError(null);
      try {
        const warmup = await navigator.mediaDevices.getUserMedia({ video: constraints, audio: false } as any);
        try { warmup.getTracks().forEach(t => t.stop()); } catch {}
        setShowCam(true);
        if (!active) toggle();
      } catch (e: any) {
        const name = e?.name || e?.message;
        if (name === "NotAllowedError") {
          setLocalError("Camera permission denied. Please enable camera access in your browser settings.");
        } else if (name === "NotFoundError" || name === "OverconstrainedError") {
          setLocalError("No suitable camera found. Try a device with a back camera.");
        } else if (name === "NotReadableError") {
          setLocalError("Camera is in use by another app. Close other apps and try again.");
        } else if (!isSecure && !isLocal) {
          setLocalError("Camera access requires HTTPS or running on http://localhost.");
        } else {
          setLocalError("Unable to access camera.");
        }
        if (active) stop();
        setShowCam(false);
      }
    }

    useEffect(() => {
      return () => { stopScan(); };
    }, [stopScan]);

    return (
      <div className="w-full max-w-md mx-auto">
        <div className="flex items-center justify-between mb-3">
          <h2 className="text-lg font-semibold">QR Scanner</h2>
          <button
            onClick={() => (isOn ? stopScan() : startScan())}
            className={`px-4 py-2 rounded text-white ${isOn ? "bg-red-600" : "bg-brand-600"}`}
          >
            {isOn ? "Stop" : "Scan Ticket"}
          </button>
        </div>

        <div className="relative rounded-lg overflow-hidden bg-black aspect-[3/4] sm:aspect-video">
          {isOn ? (
            <Webcam
              ref={webcamRef}
              audio={false}
              videoConstraints={constraints}
              mirrored={false}
              forceScreenshotSourceSize
              className="absolute inset-0 w-full h-full object-cover"
              onUserMedia={() => setLocalError(null)}
              onUserMediaError={(e) => {
                const name = (e as any)?.name || (e as any)?.message;
                const protocol = typeof window !== "undefined" ? window.location.protocol : "";
                const host = typeof window !== "undefined" ? window.location.hostname : "";
                const isLocal = host === "localhost" || host === "127.0.0.1";
                if (protocol !== "https:" && !isLocal) {
                  setLocalError("Camera access requires HTTPS or running on http://localhost.");
                  return;
                }
                if (name === "NotAllowedError") {
                  setLocalError("Camera permission denied. Please enable camera access in your browser settings.");
                } else if (name === "NotFoundError") {
                  setLocalError("No suitable camera found. Try a device with a back camera.");
                } else {
                  setLocalError("Unable to access camera.");
                }
              }}
            />
          ) : (
            <div className="absolute inset-0 flex items-center justify-center text-white/80 text-sm p-4 text-center">
              Camera is off. Tap "Scan Ticket" to start using the back camera.
            </div>
          )}
        </div>

        {(permissionError || localError) && (
          <p className="text-red-600 text-sm mt-2">{permissionError || localError}</p>
        )}
      </div>
    );
  }
);