import { useCallback, useEffect, useRef, useState } from "react";
import { Html5Qrcode } from "html5-qrcode";
import { Icon } from "./primitives/index.js";

export function CameraScanner({
  onScan,
  onClose,
}: {
  onScan: (decodedText: string) => void;
  onClose: () => void;
}) {
  const scannerRef = useRef<Html5Qrcode | null>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const [error, setError] = useState<string | null>(null);
  const [started, setStarted] = useState(false);
  const [torchOn, setTorchOn] = useState(false);
  const [torchAvailable, setTorchAvailable] = useState(false);
  const lastScan = useRef("");
  const lastScanTime = useRef(0);

  const startScanner = useCallback(async () => {
    const id = "apothecary-scanner";
    let scanner = scannerRef.current;
    if (!scanner) {
      scanner = new Html5Qrcode(id, { verbose: false });
      scannerRef.current = scanner;
    }
    if (scanner.isScanning) return;

    await scanner.start(
      { facingMode: "environment" },
      { fps: 10, qrbox: (w, h) => ({ width: Math.min(w - 40, 280), height: Math.min(h - 40, 280) }) },
      (text) => {
        const now = Date.now();
        if (text === lastScan.current && now - lastScanTime.current < 3000) return;
        lastScan.current = text;
        lastScanTime.current = now;
        onScan(text);
      },
      () => {},
    );
    setStarted(true);
    try {
      const caps = scanner.getRunningTrackCameraCapabilities();
      if (caps.torchFeature().isSupported()) {
        setTorchAvailable(true);
      }
    } catch {
      // torch check can fail on some browsers
    }
  }, [onScan]);

  const startCamera = useCallback(async () => {
    if (!window.isSecureContext) {
      setError(
        "Camera requires a secure connection (HTTPS). " +
        "Access this site over https:// or on localhost to use the scanner.",
      );
      return;
    }

    if (!navigator.mediaDevices?.getUserMedia) {
      setError("Camera API not available in this browser.");
      return;
    }

    // Request camera permission directly in the user gesture handler.
    // html5-qrcode does async DOM work before calling getUserMedia internally,
    // which breaks iOS Safari's transient user activation window.
    // By calling getUserMedia here first, we trigger the permission prompt
    // while the gesture is still active, then let html5-qrcode reuse the grant.
    let stream: MediaStream;
    try {
      stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: "environment" },
      });
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err);
      if (msg.includes("denied") || msg.includes("NotAllowedError")) {
        setError(
          "Camera permission was denied. Open your browser settings to allow camera access for this site, then try again.",
        );
      } else {
        setError(msg);
      }
      return;
    }

    // Permission granted — stop this stream so html5-qrcode can open its own
    stream.getTracks().forEach((t) => t.stop());

    try {
      await startScanner();
    } catch (err: unknown) {
      setError(err instanceof Error ? err.message : "Scanner failed to start");
    }
  }, [startScanner]);

  useEffect(() => {
    // Auto-start on desktop where getUserMedia works outside gestures
    const isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
    if (!isTouchDevice && window.isSecureContext) {
      startCamera();
    }
    return () => {
      if (scannerRef.current?.isScanning) {
        scannerRef.current.stop().catch(() => {});
      }
    };
  }, [startCamera]);

  const toggleTorch = () => {
    try {
      const caps = scannerRef.current?.getRunningTrackCameraCapabilities();
      if (caps?.torchFeature().isSupported()) {
        const next = !torchOn;
        caps.torchFeature().apply(next);
        setTorchOn(next);
      }
    } catch {
      // ignore
    }
  };

  const insecure = !window.isSecureContext;

  return (
    <div
      style={{
        position: "fixed",
        inset: 0,
        zIndex: 50,
        background: "#000",
        display: "flex",
        flexDirection: "column",
      }}
    >
      {/* Top bar */}
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          padding: "env(safe-area-inset-top, 12px) 16px 12px",
          position: "relative",
          zIndex: 2,
        }}
      >
        <button
          onClick={onClose}
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            width: 44,
            height: 44,
            borderRadius: "50%",
            background: "rgba(0,0,0,0.5)",
            border: "none",
            cursor: "pointer",
            color: "#fff",
          }}
        >
          <Icon name="close" size={22} color="#fff" />
        </button>
        <div
          className="serif"
          style={{ color: "#fff", fontSize: 18, fontWeight: 500 }}
        >
          Scan
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          {torchAvailable && (
            <button
              onClick={toggleTorch}
              style={{
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                width: 44,
                height: 44,
                borderRadius: "50%",
                background: torchOn ? "var(--sage)" : "rgba(0,0,0,0.5)",
                border: "none",
                cursor: "pointer",
                color: "#fff",
              }}
            >
              <Icon name="flash" size={20} color="#fff" />
            </button>
          )}
        </div>
      </div>

      {/* Camera viewport */}
      <div
        ref={containerRef}
        style={{ flex: 1, position: "relative", overflow: "hidden" }}
      >
        <div
          id="apothecary-scanner"
          style={{ width: "100%", height: "100%" }}
        />
        {!started && !error && (
          <div
            onClick={insecure ? undefined : startCamera}
            style={{
              position: "absolute",
              inset: 0,
              display: "flex",
              flexDirection: "column",
              alignItems: "center",
              justifyContent: "center",
              gap: 16,
              padding: 32,
              color: "#fff",
              textAlign: "center",
              cursor: insecure ? "default" : "pointer",
            }}
          >
            {insecure ? (
              <>
                <Icon name="camera" size={48} color="rgba(255,255,255,0.5)" />
                <div style={{ fontSize: 16, fontWeight: 500 }}>HTTPS required</div>
                <div style={{ fontSize: 13, opacity: 0.7, maxWidth: 300 }}>
                  Camera access requires a secure connection. Access this site
                  over <strong>https://</strong> to use the barcode scanner.
                </div>
              </>
            ) : (
              <>
                <div
                  style={{
                    width: 80,
                    height: 80,
                    borderRadius: "50%",
                    background: "var(--sage)",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                  }}
                >
                  <Icon name="camera" size={36} color="#fff" />
                </div>
                <div style={{ fontSize: 16, fontWeight: 500 }}>Tap to start camera</div>
                <div style={{ fontSize: 13, opacity: 0.7, maxWidth: 300 }}>
                  Allow camera access when prompted
                </div>
              </>
            )}
          </div>
        )}
        {error && (
          <div
            style={{
              position: "absolute",
              inset: 0,
              display: "flex",
              flexDirection: "column",
              alignItems: "center",
              justifyContent: "center",
              gap: 16,
              padding: 32,
              color: "#fff",
              textAlign: "center",
            }}
          >
            <Icon name="camera" size={48} color="rgba(255,255,255,0.5)" />
            <div style={{ fontSize: 16, fontWeight: 500 }}>Camera unavailable</div>
            <div style={{ fontSize: 13, opacity: 0.7, maxWidth: 300 }}>{error}</div>
            {!insecure && (
              <button
                onClick={() => { setError(null); startCamera(); }}
                style={{
                  marginTop: 8,
                  padding: "10px 24px",
                  borderRadius: 8,
                  background: "var(--sage)",
                  color: "#fff",
                  border: "none",
                  fontSize: 14,
                  fontWeight: 500,
                  cursor: "pointer",
                }}
              >
                Try again
              </button>
            )}
          </div>
        )}
      </div>

      {/* Bottom hint */}
      <div
        style={{
          padding: "16px 24px",
          paddingBottom: "calc(16px + env(safe-area-inset-bottom, 0px))",
          textAlign: "center",
          color: "rgba(255,255,255,0.7)",
          fontSize: 14,
        }}
      >
        {started ? "Point at a barcode or QR code" : ""}
      </div>
    </div>
  );
}
