import { useState, useEffect, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { RefreshCw } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectLabel,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { useClient } from 'hooks/useClient';

type Provider = 'openai' | 'elevenlabs';

type TtsConfig = {
  provider: Provider;
  url: string;
  apiKey?: string;
  model: string;
  voice: string;
};

const PROVIDER_DEFAULTS: Record<Provider, Partial<TtsConfig>> = {
  openai: { url: 'http://localhost:64202', model: 'kokoro', voice: 'af_heart' },
  elevenlabs: { url: '', model: 'eleven_multilingual_v2', voice: 'Rachel' },
};

export const TTSSection = () => {
  const client = useClient();
  const queryClient = useQueryClient();
  const audioRef = useRef<HTMLAudioElement | null>(null);

  const { data: config, isLoading } = useQuery({
    queryKey: ['TTS_CONFIG'],
    queryFn: () => client.get<TtsConfig | null>('/server-settings/tts'),
  });

  const [provider, setProvider] = useState<Provider>('openai');
  const [url, setUrl] = useState('http://localhost:64202');
  const [apiKey, setApiKey] = useState('');
  const [model, setModel] = useState('kokoro');
  const [voice, setVoice] = useState('af_heart');
  const [voices, setVoices] = useState<string[]>([]);
  const [voiceGroups, setVoiceGroups] = useState<{ label: string; voices: string[] }[]>([]);
  const [voicesLoading, setVoicesLoading] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [isTesting, setIsTesting] = useState(false);

  const fetchVoices = async (p: Provider, u: string, key: string, m?: string) => {
    setVoicesLoading(true);
    try {
      const res = await client.post<{
        voices?: string[];
        groups?: { label: string; voices: string[] }[];
        error?: string;
      }>('/server-settings/tts/voices', {
        provider: p,
        url: u,
        apiKey: key || undefined,
        model: m || undefined,
      });
      if (res.voices) setVoices(res.voices);
      else setVoices([]);
      setVoiceGroups(res.groups ?? []);
    } catch {
      setVoices([]);
    } finally {
      setVoicesLoading(false);
    }
  };

  useEffect(() => {
    if (!config) return;
    setProvider(config.provider);
    setUrl(config.url ?? '');
    setApiKey(config.apiKey ?? '');
    setModel(config.model);
    setVoice(config.voice);
    fetchVoices(config.provider, config.url ?? '', config.apiKey ?? '', config.model);
  }, [config]);

  const handleProviderChange = (v: Provider) => {
    setProvider(v);
    const defaults = PROVIDER_DEFAULTS[v];
    if (defaults.url !== undefined) setUrl(defaults.url);
    if (defaults.model !== undefined) setModel(defaults.model);
    if (defaults.voice !== undefined) setVoice(defaults.voice);
    setApiKey('');
  };

  const buildConfig = (): TtsConfig => ({
    provider,
    url,
    model,
    voice,
    ...(apiKey ? { apiKey } : {}),
  });

  const handleSave = async () => {
    if (isSaving) return;
    setIsSaving(true);
    try {
      await client.put('/server-settings/tts', buildConfig());
      queryClient.invalidateQueries({ queryKey: ['TTS_CONFIG'] });
      toast.success('TTS settings saved');
    } catch {
      toast.error('Failed to save TTS settings');
    } finally {
      setIsSaving(false);
    }
  };

  const handleTest = async () => {
    if (isTesting) return;
    setIsTesting(true);
    try {
      const res = await fetch(`${client.baseUrl}/server-settings/tts/test`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${client.token}` },
        body: JSON.stringify(buildConfig()),
      });

      if (!res.ok || res.headers.get('content-type')?.includes('json')) {
        const json = await res.json().catch(() => ({ error: 'Test failed' }));
        toast.error(json.error ?? 'Test failed');
        return;
      }

      const blob = await res.blob();
      const audioUrl = URL.createObjectURL(blob);
      if (audioRef.current) {
        audioRef.current.pause();
        URL.revokeObjectURL(audioRef.current.src);
      }
      const audio = new Audio(audioUrl);
      audioRef.current = audio;
      audio.play();
      toast.success('Playing test audio');
    } catch {
      toast.error('Test failed — could not reach TTS server');
    } finally {
      setIsTesting(false);
    }
  };

  if (isLoading) return <p className="text-sm text-duck-dark/40">Loading...</p>;

  return (
    <div className="grid gap-4">
      <Label className="grid gap-2">
        <span className="text-duck-dark/70 dark:text-foreground/70">Provider</span>
        <Select value={provider} onValueChange={(v) => handleProviderChange(v as Provider)}>
          <SelectTrigger className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark dark:text-foreground">
            <SelectValue />
          </SelectTrigger>
          <SelectContent className="z-[600]">
            <SelectItem value="openai">OpenAI-compatible (Kokoro, OpenAI, etc.)</SelectItem>
            <SelectItem value="elevenlabs">ElevenLabs</SelectItem>
          </SelectContent>
        </Select>
      </Label>

      {provider === 'openai' && (
        <Label className="grid gap-2">
          <span className="text-duck-dark/70 dark:text-foreground/70">URL</span>
          <Input
            className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark dark:text-foreground placeholder:text-duck-dark/40"
            placeholder="http://localhost:64202"
            value={url}
            onChange={(ev) => setUrl(ev.target.value)}
          />
        </Label>
      )}

      <Label className="grid gap-2">
        <span className="text-duck-dark/70 dark:text-foreground/70">
          API Key {provider === 'openai' ? '(optional)' : ''}
        </span>
        <Input
          type="password"
          className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark dark:text-foreground placeholder:text-duck-dark/40"
          placeholder={provider === 'elevenlabs' ? 'xi-...' : 'sk-...'}
          value={apiKey}
          onChange={(ev) => setApiKey(ev.target.value)}
        />
      </Label>

      <div className="grid grid-cols-2 gap-2">
        <Label className="grid gap-2">
          <span className="text-duck-dark/70 dark:text-foreground/70">Model</span>
          <Input
            className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark dark:text-foreground placeholder:text-duck-dark/40"
            placeholder={provider === 'openai' ? 'kokoro' : 'eleven_multilingual_v2'}
            value={model}
            onChange={(ev) => setModel(ev.target.value)}
          />
        </Label>
        <Label className="grid gap-2">
          <div className="flex items-center gap-1.5">
            <span className="text-duck-dark/70 dark:text-foreground/70">Voice</span>
            <button
              type="button"
              onClick={() => fetchVoices(provider, url, apiKey, model)}
              disabled={voicesLoading}
              className="p-0.5 rounded hover:bg-duck-dark/10 dark:hover:bg-foreground/10 cursor-pointer transition-colors disabled:opacity-40"
              title="Refresh voices"
            >
              <RefreshCw
                className={`h-3 w-3 text-duck-dark/50 dark:text-foreground/50 ${voicesLoading ? 'animate-spin' : ''}`}
              />
            </button>
          </div>
          {voices.length > 0 ? (
            <Select value={voice} onValueChange={setVoice}>
              <SelectTrigger className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark dark:text-foreground">
                <SelectValue placeholder="Select a voice" />
              </SelectTrigger>
              <SelectContent className="z-[600] max-h-[300px]">
                {voiceGroups.length > 0
                  ? voiceGroups.map((g) => (
                      <SelectGroup key={g.label}>
                        <SelectLabel className="text-xs font-semibold text-duck-dark/50 dark:text-foreground/50">
                          {g.label}
                        </SelectLabel>
                        {g.voices.map((v) => (
                          <SelectItem key={v} value={v}>
                            {v.replace(/^[a-z]{2}_/, '').replace(/^\w/, (c) => c.toUpperCase())}
                          </SelectItem>
                        ))}
                      </SelectGroup>
                    ))
                  : voices.map((v) => (
                      <SelectItem key={v} value={v}>
                        {v}
                      </SelectItem>
                    ))}
              </SelectContent>
            </Select>
          ) : (
            <Input
              className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark dark:text-foreground placeholder:text-duck-dark/40"
              placeholder={provider === 'openai' ? 'af_heart' : 'Rachel'}
              value={voice}
              onChange={(ev) => setVoice(ev.target.value)}
            />
          )}
        </Label>
      </div>

      <div className="flex items-center gap-2">
        <Button
          type="button"
          onClick={handleSave}
          disabled={isSaving}
          className="flex-1 h-11 bg-duck-yellow hover:bg-duck-yellow/90 text-duck-teal font-bold transition-all duration-200 hover:scale-105 cursor-pointer disabled:opacity-50 disabled:hover:scale-100"
        >
          {isSaving ? 'Saving...' : 'Save'}
        </Button>
        <Button
          type="button"
          variant="outline"
          onClick={handleTest}
          disabled={isTesting}
          className="h-11 cursor-pointer disabled:opacity-50"
        >
          {isTesting ? 'Testing...' : 'Test'}
        </Button>
      </div>
    </div>
  );
};
