"use client";

import { Check, Clock3, LoaderCircle, MessageSquareText, PhoneCall, ShieldCheck, Volume2 } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { useTenant } from "@/components/tenant-provider";

type VoiceOtpPanelProps = {
  phone: string;
  purpose: "signup" | "checkout";
  onVerified: (token: string) => void;
  compact?: boolean;
};

type StartResponse = {
  verificationId?: number;
  phone?: string;
  delivery?: "mobile_call" | "browser_voice_sandbox";
  sandboxCode?: string;
  message?: string;
  error?: string;
};

export default function VoiceOtpPanel({ phone, purpose, onVerified, compact = false }: VoiceOtpPanelProps) {
  const { tenant } = useTenant();
  const [verificationId, setVerificationId] = useState<number | null>(null);
  const [normalizedPhone, setNormalizedPhone] = useState("");
  const [delivery, setDelivery] = useState<StartResponse["delivery"]>();
  const [sandboxCode, setSandboxCode] = useState("");
  const [code, setCode] = useState("");
  const [loading, setLoading] = useState(false);
  const [checking, setChecking] = useState(false);
  const [error, setError] = useState("");
  const [countdown, setCountdown] = useState(0);
  const [verified, setVerified] = useState(false);

  useEffect(() => {
    if (countdown <= 0) return;
    const timer = window.setInterval(() => setCountdown((value) => Math.max(0, value - 1)), 1000);
    return () => window.clearInterval(timer);
  }, [countdown]);

  const maskedPhone = useMemo(() => {
    const digits = (normalizedPhone || phone).replace(/\D/g, "");
    return digits.length > 4 ? `+${digits.slice(0, 2)} •••••• ${digits.slice(-4)}` : phone;
  }, [normalizedPhone, phone]);

  function speakSandboxCode(value = sandboxCode) {
    if (!value || typeof window === "undefined" || !("speechSynthesis" in window)) return;
    window.speechSynthesis.cancel();
    const digits = value.split("").join(". ");
    const message = new SpeechSynthesisUtterance(`Hello from ${tenant.brandName}. Your verification code is ${digits}. I repeat, ${digits}.`);
    message.rate = 0.78;
    message.pitch = 1;
    window.speechSynthesis.speak(message);
  }

  async function startCall() {
    setLoading(true);
    setError("");
    try {
      const response = await fetch("/api/auth/otp/start", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ phone, purpose, channel: "call" }),
      });
      const data = (await response.json()) as StartResponse;
      if (!response.ok || !data.verificationId || !data.phone) throw new Error(data.error || "Could not place the call.");
      setVerificationId(data.verificationId);
      setNormalizedPhone(data.phone);
      setDelivery(data.delivery);
      setSandboxCode(data.sandboxCode ?? "");
      setCountdown(45);
      setCode("");
      if (data.delivery === "browser_voice_sandbox" && data.sandboxCode) {
        window.setTimeout(() => speakSandboxCode(data.sandboxCode), 450);
      }
    } catch (reason) {
      setError(reason instanceof Error ? reason.message : "Could not place the verification call.");
    } finally {
      setLoading(false);
    }
  }

  async function checkCode() {
    if (!verificationId || code.length !== 6) return;
    setChecking(true);
    setError("");
    try {
      const response = await fetch("/api/auth/otp/check", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ verificationId, phone: normalizedPhone || phone, purpose, code }),
      });
      const data = (await response.json()) as { verificationToken?: string; error?: string };
      if (!response.ok || !data.verificationToken) throw new Error(data.error || "Verification failed.");
      setVerified(true);
      onVerified(data.verificationToken);
    } catch (reason) {
      setError(reason instanceof Error ? reason.message : "Verification failed.");
    } finally {
      setChecking(false);
    }
  }

  if (verified) {
    return (
      <div className="flex items-center gap-3 rounded-xl border border-green-200 bg-green-50 p-3 text-green-800">
        <span className="grid h-8 w-8 place-items-center rounded-full bg-green-600 text-white"><Check size={16} strokeWidth={3} /></span>
        <div><p className="text-xs font-black">Mobile number verified</p><p className="mt-0.5 text-[10px] text-green-700">Voice verification completed for {maskedPhone}</p></div>
      </div>
    );
  }

  return (
    <div className={`rounded-2xl border border-blue-200 bg-blue-50/70 ${compact ? "p-3" : "p-5"}`}>
      <div className="flex items-start gap-3">
        <span className="grid h-10 w-10 shrink-0 place-items-center rounded-xl bg-[#155ee9] text-white"><PhoneCall size={19} /></span>
        <div className="flex-1">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <div><p className="text-sm font-black text-[#11203e]">Verify by voice call</p><p className="mt-1 text-[10px] leading-4 text-slate-500">We&apos;ll call {maskedPhone} and read a 6-digit OTP.</p></div>
            <span className="rounded-full bg-white px-2 py-1 text-[8px] font-black uppercase tracking-wider text-[#155ee9]">Voice only</span>
          </div>

          {!verificationId ? (
            <div className="mt-4 grid gap-2 sm:grid-cols-2">
              <button type="button" onClick={() => void startCall()} disabled={loading || phone.replace(/\D/g, "").length < 10} className="flex items-center justify-center gap-2 rounded-xl bg-[#155ee9] px-4 py-3 text-xs font-black text-white disabled:opacity-50">{loading ? <LoaderCircle size={15} className="animate-spin" /> : <PhoneCall size={15} />} Call me with OTP</button>
              <button type="button" disabled className="flex items-center justify-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-3 text-xs font-black text-slate-400"><MessageSquareText size={15} /> Text SMS — coming soon</button>
            </div>
          ) : (
            <div className="mt-4">
              <div className="flex gap-2">
                <input value={code} onChange={(event) => setCode(event.target.value.replace(/\D/g, "").slice(0, 6))} onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); void checkCode(); } }} inputMode="numeric" autoComplete="one-time-code" placeholder="Enter 6-digit OTP" className="h-11 min-w-0 flex-1 rounded-xl border border-blue-200 bg-white px-3 text-center text-sm font-black tracking-[0.28em] outline-none focus:border-[#155ee9]" aria-label="Voice OTP code" />
                <button type="button" onClick={() => void checkCode()} disabled={checking || code.length !== 6} className="flex items-center gap-2 rounded-xl bg-[#155ee9] px-4 text-xs font-black text-white disabled:opacity-50">{checking && <LoaderCircle size={14} className="animate-spin" />} Verify</button>
              </div>
              <div className="mt-3 flex flex-wrap items-center justify-between gap-2 text-[10px]">
                <p className="flex items-center gap-1 text-slate-500"><Clock3 size={12} /> Answer the call and listen carefully.</p>
                <div className="flex items-center gap-3">
                  {delivery === "browser_voice_sandbox" && <button type="button" onClick={() => speakSandboxCode()} className="flex items-center gap-1 font-black text-violet-600"><Volume2 size={13} /> Hear code again</button>}
                  <button type="button" disabled={countdown > 0 || loading} onClick={() => void startCall()} className="font-black text-[#155ee9] disabled:text-slate-400">{countdown > 0 ? `Call again in ${countdown}s` : "Call again"}</button>
                </div>
              </div>
              {delivery === "browser_voice_sandbox" && <p className="mt-3 rounded-lg bg-violet-50 px-3 py-2 text-[9px] leading-4 text-violet-700">Sandbox voice is active because Twilio credentials are not configured. Production uses a real mobile call.</p>}
            </div>
          )}
          {error && <p className="mt-3 rounded-lg bg-red-50 px-3 py-2 text-[10px] font-bold text-red-600">{error}</p>}
          <p className="mt-3 flex items-center gap-1 text-[9px] text-slate-400"><ShieldCheck size={11} /> OTP expires in 10 minutes and is never stored in plain text.</p>
        </div>
      </div>
    </div>
  );
}
