/**
 * @license
 * SPDX-License-Identifier: Apache-2.0
 */

import React, { useState, useEffect, useRef } from 'react';
import { Property } from '../types';
import { motion, AnimatePresence } from 'motion/react';
import { 
  Mic, 
  MicOff, 
  X, 
  Sparkles, 
  Volume2, 
  VolumeX, 
  Search, 
  BookmarkCheck, 
  HelpCircle, 
  Info, 
  AlertCircle 
} from 'lucide-react';

interface VoiceAssistantProps {
  properties: Property[];
  searchQuery: string;
  onSearchChange: (query: string) => void;
  onTypeFilterChange: (type: 'all' | 'charging' | 'parking' | 'both' | 'favorites') => void;
  onSelectProperty: (propertyId: string) => void;
  onBookProperty: (property: Property) => void;
  setDriverPage: (page: 'explore' | 'bookings' | 'profile' | 'help' | 'repair') => void;
}

export default function VoiceAssistant({
  properties,
  searchQuery,
  onSearchChange,
  onTypeFilterChange,
  onSelectProperty,
  onBookProperty,
  setDriverPage
}: VoiceAssistantProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [isListening, setIsListening] = useState(false);
  const [transcript, setTranscript] = useState('');
  const [interimTranscript, setInterimTranscript] = useState('');
  const [assistantMessage, setAssistantMessage] = useState('How can I help you find charging or parking in Bihar?');
  const [isMuted, setIsMuted] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const recognitionRef = useRef<any>(null);
  const isOpenRef = useRef(isOpen);
  const transcriptRef = useRef('');
  const interimTranscriptRef = useRef('');
  const hasErrorRef = useRef(false);

  // Sync isOpen to a ref to let async SpeechRecognition callbacks safely read it
  useEffect(() => {
    isOpenRef.current = isOpen;
  }, [isOpen]);

  // Cleanup SpeechRecognition on component unmount
  useEffect(() => {
    return () => {
      if (recognitionRef.current) {
        try {
          recognitionRef.current.abort();
        } catch (e) {
          console.error('Failed to abort speech recognition on unmount', e);
        }
      }
    };
  }, []);

  // Text to Speech Helper
  const speak = (message: string) => {
    if (isMuted || !isOpenRef.current) return;
    if ('speechSynthesis' in window) {
      window.speechSynthesis.cancel();
      const utterance = new SpeechSynthesisUtterance(message);
      utterance.rate = 1.0;
      utterance.pitch = 1.0;
      
      // Try to find an Indian English voice if available for localized feel
      const voices = window.speechSynthesis.getVoices();
      const indVoice = voices.find(v => v.lang.includes('EN-IN') || v.lang.includes('en-IN'));
      if (indVoice) {
        utterance.voice = indVoice;
      }
      
      window.speechSynthesis.speak(utterance);
    }
  };

  useEffect(() => {
    // Pre-load voices so getVoices is populated
    if ('speechSynthesis' in window) {
      window.speechSynthesis.getVoices();
    }
  }, []);

  const startListening = () => {
    setError(null);
    setTranscript('');
    setInterimTranscript('');
    transcriptRef.current = '';
    interimTranscriptRef.current = '';
    hasErrorRef.current = false;
    setAssistantMessage('Listening...');

    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
    
    if (!SpeechRecognition) {
      setError('Speech recognition is not supported in this browser. Please try Chrome, Edge, or Safari.');
      setAssistantMessage('Speech recognition is not supported.');
      speak('Speech recognition is not supported in your browser.');
      return;
    }

    try {
      const rec = new SpeechRecognition();
      rec.continuous = false;
      rec.interimResults = true;
      rec.lang = 'en-IN'; // Set to Indian English for better recognition of local Bihar place names

      rec.onstart = () => {
        if (!isOpenRef.current) {
          try { rec.abort(); } catch {}
          return;
        }
        setIsListening(true);
      };

      rec.onresult = (event: any) => {
        if (!isOpenRef.current) return;
        let interim = '';
        let final = '';

        for (let i = event.resultIndex; i < event.results.length; ++i) {
          if (event.results[i].isFinal) {
            final += event.results[i][0].transcript;
          } else {
            interim += event.results[i][0].transcript;
          }
        }

        if (final) {
          setTranscript(final);
          transcriptRef.current = final;
        }
        setInterimTranscript(interim);
        interimTranscriptRef.current = interim;
      };

      rec.onerror = (event: any) => {
        if (!isOpenRef.current) return;
        console.warn('Speech recognition error event:', event.error);
        hasErrorRef.current = true;

        if (event.error === 'not-allowed') {
          setError('Microphone permission denied. Please allow microphone access in your browser.');
          setAssistantMessage('Microphone access denied. Please allow microphone permissions.');
          speak('Please allow microphone access.');
        } else if (event.error === 'aborted') {
          // 'aborted' is triggered when stop() is called manually or system aborts.
          // No need to show a red error banner to the user.
          setAssistantMessage('Listening stopped.');
        } else if (event.error === 'no-speech') {
          setAssistantMessage('I didn\'t hear any speech. Try saying "Find parking in Sasaram".');
          speak('I didn\'t hear any speech.');
        } else {
          setError(`Error occurred: ${event.error}`);
          setAssistantMessage('I could not hear you properly.');
        }
        setIsListening(false);
      };

      rec.onend = () => {
        if (!isOpenRef.current) return;
        setIsListening(false);

        // If an error occurred (such as aborted or no-speech), the error handler
        // has already updated the message and spoken to the user. Do not overwrite.
        if (hasErrorRef.current) {
          return;
        }

        const finalQuery = transcriptRef.current || interimTranscriptRef.current;
        if (finalQuery) {
          processVoiceCommand(finalQuery);
        } else {
          setAssistantMessage('I didn\'t catch that. Try saying "Find parking in Sasaram".');
          speak('I didn\'t catch that. Please try again.');
        }
      };

      recognitionRef.current = rec;
      rec.start();
    } catch (e: any) {
      setError(`Failed to initialize speech: ${e.message}`);
      setIsListening(false);
    }
  };

  const stopListening = () => {
    if (recognitionRef.current) {
      try {
        recognitionRef.current.stop();
      } catch (e) {
        console.warn('Failed to stop speech recognition cleanly:', e);
      }
    }
    setIsListening(false);
  };

  // Semantic Speech Analyzer and Execution Engine
  const processVoiceCommand = (rawText: string) => {
    const text = rawText.toLowerCase().trim();
    console.log("Analyzing speech command:", text);

    // Identify target cities/regions in Bihar
    const cities = ['sasaram', 'nokha', 'bikramganj', 'kaimur', 'mohaniya', 'bhabua', 'patna', 'gaya'];
    let matchedCity = '';
    for (const city of cities) {
      if (text.includes(city)) {
        matchedCity = city;
        break;
      }
    }

    // Identify facility type
    let targetType: 'all' | 'charging' | 'parking' | 'both' = 'all';
    if (text.includes('charging') || text.includes('charger') || text.includes('charge')) {
      targetType = text.includes('parking') || text.includes('park') ? 'both' : 'charging';
    } else if (text.includes('parking') || text.includes('park') || text.includes('slot')) {
      targetType = 'parking';
    }

    // Determine if user wants to BOOK
    const isBookingRequest = text.includes('book') || text.includes('reserve') || text.includes('rent') || text.includes('schedule');

    // 1. Direct match with specific property keywords
    let matchedProperty: Property | null = null;
    let highestScore = 0;

    for (const prop of properties) {
      let score = 0;
      const title = prop.title.toLowerCase();
      const address = prop.location.address.toLowerCase();

      // Look for specific landmark names
      if (text.includes('junction') && title.includes('junction')) score += 5;
      if (text.includes('pilotbaba') && (title.includes('pilotbaba') || address.includes('pilot baba'))) score += 5;
      if (text.includes('hanuman') && title.includes('hanuman')) score += 5;
      if (text.includes('kali mandir') && title.includes('kali mandir')) score += 5;
      if (text.includes('police station') && title.includes('police station')) score += 5;
      if (text.includes('sabji mandi') && title.includes('sabji mandi')) score += 5;
      if (text.includes('nirvana') && title.includes('nirvana')) score += 5;
      if (text.includes('ashkamini') && title.includes('ashkamini')) score += 5;
      if (text.includes('petrol pump') && (title.includes('petrol pump') || title.includes('fuel'))) score += 5;
      if (text.includes('pani tanki') && title.includes('pani tanki')) score += 5;
      if (text.includes('gandhi maidan') && title.includes('gandhi maidan')) score += 5;
      if (text.includes('patliputra') && title.includes('patliputra')) score += 5;
      if (text.includes('dak bunglow') && title.includes('dak bunglow')) score += 5;
      if (text.includes('sports complex') && title.includes('sports complex')) score += 5;
      if (text.includes('vishnupad') && title.includes('vishnupad')) score += 5;
      if (text.includes('mahabodhi') && title.includes('mahabodhi')) score += 5;
      if (text.includes('ap colony') && title.includes('ap colony')) score += 5;

      // Check general location
      if (matchedCity && prop.location.city.toLowerCase().includes(matchedCity)) {
        score += 2;
      }

      if (score > highestScore) {
        highestScore = score;
        matchedProperty = prop;
      }
    }

    // Execute corresponding action
    if (isBookingRequest && matchedProperty) {
      // Direct Booking flow
      setDriverPage('explore');
      onSearchChange('');
      onSelectProperty(matchedProperty.id);
      onBookProperty(matchedProperty);
      
      const reply = `Sure! Opening the booking form for ${matchedProperty.title} in ${matchedProperty.location.city}. Please fill in your vehicle details to reserve.`;
      setAssistantMessage(reply);
      speak(reply);
    } else if (matchedProperty && text.includes('find') && highestScore >= 5) {
      // Find a specific spot
      setDriverPage('explore');
      onSearchChange(matchedProperty.title);
      onSelectProperty(matchedProperty.id);
      
      const reply = `I found "${matchedProperty.title}" for you. Selecting it on the map now.`;
      setAssistantMessage(reply);
      speak(reply);
    } else if (matchedCity) {
      // Location filtering
      setDriverPage('explore');
      
      // Normalize casing
      const formattedCity = matchedCity.charAt(0).toUpperCase() + matchedCity.slice(1);
      
      // Update filters
      onSearchChange(formattedCity);
      if (targetType !== 'all') {
        onTypeFilterChange(targetType);
      }

      // Count matches
      const matches = properties.filter(p => 
        p.location.city.toLowerCase().includes(matchedCity) &&
        (targetType === 'all' || p.type === targetType || p.type === 'both')
      );

      let reply = `Filtering results for ${targetType === 'all' ? '' : targetType} spots in ${formattedCity}. I found ${matches.length} stations.`;
      if (isBookingRequest && matches.length > 0) {
        // If they said "book parking in Sasaram", open the first match
        const firstSpot = matches[0];
        onSelectProperty(firstSpot.id);
        onBookProperty(firstSpot);
        reply = `Found ${matches.length} locations in ${formattedCity}. Opening booking panel for the top-rated one: ${firstSpot.title}.`;
      }

      setAssistantMessage(reply);
      speak(reply);
    } else if (targetType !== 'all') {
      // Global category filtering
      setDriverPage('explore');
      onTypeFilterChange(targetType);
      const reply = `Showing all electric vehicle ${targetType} spots.`;
      setAssistantMessage(reply);
      speak(reply);
    } else {
      // fallback search query
      setDriverPage('explore');
      onSearchChange(rawText);
      const reply = `Searching the map for "${rawText}".`;
      setAssistantMessage(reply);
      speak(reply);
    }
  };

  const handleOpen = () => {
    setIsOpen(true);
    setTranscript('');
    setInterimTranscript('');
    setError(null);
    setAssistantMessage('Hi there! Ask me to "Find parking in Sasaram" or "Book Mahabodhi Temple charging spot".');
    // Speak welcome
    speak('Hi there! How can I help you find charging or parking in Bihar?');
  };

  const handleClose = () => {
    stopListening();
    if ('speechSynthesis' in window) {
      window.speechSynthesis.cancel();
    }
    setIsOpen(false);
  };

  return (
    <>
      {/* Absolute styled micro trigger inside search bars */}
      <button
        type="button"
        onClick={handleOpen}
        title="Voice Search Assistant"
        className="absolute right-12 top-3 p-1 rounded-lg bg-slate-950 border border-slate-800 hover:border-amber-500 hover:bg-slate-850 text-amber-500 transition-all cursor-pointer flex items-center justify-center select-none"
        id="voice-assistant-trigger"
      >
        <Mic className="w-4 h-4 animate-pulse" />
      </button>

      {/* Voice Assistant Modal Dialogue Overlay */}
      <AnimatePresence>
        {isOpen && (
          <div className="fixed inset-0 z-55 overflow-y-auto bg-slate-950/80 p-4 flex items-center justify-center backdrop-blur-md">
            <motion.div
              initial={{ scale: 0.94, opacity: 0 }}
              animate={{ scale: 1, opacity: 1 }}
              exit={{ scale: 0.94, opacity: 0 }}
              className="w-full max-w-md bg-slate-900 border border-slate-800 rounded-3xl overflow-hidden shadow-2xl relative p-6"
            >
              {/* Header */}
              <div className="flex items-center justify-between pb-4 border-b border-slate-850">
                <div className="flex items-center gap-2">
                  <div className="p-2 bg-amber-500/10 text-amber-500 rounded-xl border border-amber-900/20">
                    <Sparkles className="w-4 h-4" />
                  </div>
                  <div>
                    <h3 className="font-extrabold text-white text-sm">Bihar EV Voice Companion</h3>
                    <p className="text-[9px] font-mono text-slate-500 font-bold uppercase tracking-widest">Al-POWERED ASSISTANT</p>
                  </div>
                </div>

                <div className="flex items-center gap-2">
                  {/* Mute button */}
                  <button
                    type="button"
                    onClick={() => {
                      const newMuted = !isMuted;
                      setIsMuted(newMuted);
                      if (newMuted && 'speechSynthesis' in window) {
                        window.speechSynthesis.cancel();
                      }
                    }}
                    className={`p-1.5 rounded-lg border transition-colors ${isMuted ? 'bg-slate-950 text-slate-500 border-slate-850' : 'bg-amber-500/10 text-amber-500 border-amber-900/15 hover:bg-amber-500/20'}`}
                  >
                    {isMuted ? <VolumeX className="w-3.5 h-3.5" /> : <Volume2 className="w-3.5 h-3.5" />}
                  </button>

                  <button
                    type="button"
                    onClick={handleClose}
                    className="p-1.5 rounded-lg bg-slate-950 border border-slate-850 hover:bg-slate-800 text-slate-400 hover:text-white transition-colors"
                  >
                    <X className="w-4 h-4" />
                  </button>
                </div>
              </div>

              {/* Body message display */}
              <div className="py-6 space-y-6 text-center select-none">
                
                {/* Assistant Output Speech Bubble */}
                <div className="bg-slate-950 border border-slate-850 p-4 rounded-2xl relative text-left">
                  <div className="absolute top-2 left-3 flex items-center gap-1">
                    <span className="w-1.5 h-1.5 bg-amber-500 rounded-full"></span>
                    <span className="text-[8px] font-bold text-slate-500 tracking-wider font-mono uppercase">Companion</span>
                  </div>
                  <p className="text-slate-200 text-xs sm:text-sm font-semibold leading-relaxed pt-2">
                    {assistantMessage}
                  </p>
                </div>

                {/* Simulated Waveform Visualizer when listening */}
                <div className="h-16 flex items-center justify-center gap-1.5">
                  {isListening ? (
                    <>
                      {[...Array(9)].map((_, i) => (
                        <motion.div
                          key={i}
                          animate={{
                            height: [16, Math.floor(Math.random() * 48) + 12, 16],
                          }}
                          transition={{
                            duration: 0.6 + i * 0.08,
                            repeat: Infinity,
                            ease: 'easeInOut',
                          }}
                          className="w-1 rounded-full bg-gradient-to-t from-amber-500 to-amber-300"
                        />
                      ))}
                    </>
                  ) : (
                    <div className="w-16 h-1 bg-slate-800 rounded-full" />
                  )}
                </div>

                {/* Spoken transcript output */}
                {(transcript || interimTranscript) && (
                  <div className="space-y-1.5 text-left bg-slate-950/40 p-3 rounded-xl border border-slate-850">
                    <span className="text-[8px] font-black text-slate-500 font-mono tracking-wider block uppercase">YOU SAID:</span>
                    <p className="text-xs font-semibold text-slate-300 italic">
                      "{transcript || interimTranscript}"
                    </p>
                  </div>
                )}

                {/* Error Banner if any */}
                {error && (
                  <div className="p-3 bg-rose-950/20 border border-rose-900/30 text-rose-400 rounded-xl flex items-start gap-2 text-left text-[11px] leading-snug">
                    <AlertCircle className="w-4 h-4 text-rose-500 shrink-0 mt-0.5" />
                    <span>{error}</span>
                  </div>
                )}

                {/* Large Microphone Core Button */}
                <div className="flex flex-col items-center gap-2">
                  <button
                    type="button"
                    onClick={isListening ? stopListening : startListening}
                    className={`w-20 h-20 rounded-full flex items-center justify-center transition-all duration-300 relative select-none cursor-pointer
                      ${isListening 
                        ? 'bg-rose-600 hover:bg-rose-500 text-white shadow-lg shadow-rose-600/20 ring-4 ring-rose-500/20' 
                        : 'bg-gradient-to-br from-amber-500 to-amber-600 text-slate-950 hover:scale-105 shadow-xl shadow-amber-500/10'
                      }`}
                  >
                    {isListening ? (
                      <MicOff className="w-8 h-8 stroke-[2.5] animate-pulse" />
                    ) : (
                      <Mic className="w-8 h-8 stroke-[2.5]" />
                    )}
                    {isListening && (
                      <span className="absolute inset-0 rounded-full border-4 border-rose-400/40 animate-ping" />
                    )}
                  </button>
                  <span className="text-[10px] font-bold text-slate-500 tracking-wide uppercase font-mono mt-1">
                    {isListening ? 'Click to stop & analyze' : 'Click mic to talk'}
                  </span>
                </div>
              </div>

              {/* Suggestions Helper section */}
              <div className="bg-slate-950/50 p-4 rounded-2xl border border-slate-850/80 space-y-2.5">
                <span className="text-[9px] font-black text-slate-400 font-mono tracking-widest block uppercase">TIPS ON WHAT TO ASK:</span>
                <div className="grid grid-cols-1 gap-1.5">
                  <button
                    type="button"
                    onClick={() => {
                      setTranscript("Find parking in Sasaram");
                      processVoiceCommand("Find parking in Sasaram");
                    }}
                    className="flex items-center gap-2 text-[11px] text-slate-400 hover:text-white transition-colors text-left py-1 px-1.5 rounded hover:bg-slate-900 font-medium"
                  >
                    <Search className="w-3.5 h-3.5 text-amber-500" />
                    <span>"Find parking in Sasaram"</span>
                  </button>

                  <button
                    type="button"
                    onClick={() => {
                      setTranscript("Book Sasaram Junction");
                      processVoiceCommand("Book Sasaram Junction");
                    }}
                    className="flex items-center gap-2 text-[11px] text-slate-400 hover:text-white transition-colors text-left py-1 px-1.5 rounded hover:bg-slate-900 font-medium"
                  >
                    <BookmarkCheck className="w-3.5 h-3.5 text-emerald-500" />
                    <span>"Book Sasaram Junction parking"</span>
                  </button>

                  <button
                    type="button"
                    onClick={() => {
                      setTranscript("Find charging in Patna");
                      processVoiceCommand("Find charging in Patna");
                    }}
                    className="flex items-center gap-2 text-[11px] text-slate-400 hover:text-white transition-colors text-left py-1 px-1.5 rounded hover:bg-slate-900 font-medium"
                  >
                    <Search className="w-3.5 h-3.5 text-amber-500" />
                    <span>"Find charging in Patna"</span>
                  </button>

                  <button
                    type="button"
                    onClick={() => {
                      setTranscript("Book Mahabodhi Temple EV charging");
                      processVoiceCommand("Book Mahabodhi Temple EV charging");
                    }}
                    className="flex items-center gap-2 text-[11px] text-slate-400 hover:text-white transition-colors text-left py-1 px-1.5 rounded hover:bg-slate-900 font-medium"
                  >
                    <BookmarkCheck className="w-3.5 h-3.5 text-emerald-500" />
                    <span>"Book Mahabodhi Temple EV charging"</span>
                  </button>
                </div>
              </div>
            </motion.div>
          </div>
        )}
      </AnimatePresence>
    </>
  );
}
