"use client";

import { ChangeEvent, useEffect, useState } from "react";
import Button from "@/components/Button";
import IconClick from "@/components/IconClick";
import { useAudioPlayer } from "@/hooks/useAudioPlayer";
import IMAGES from "@/config/images";
import { getTTSAudioUrl } from "@/utils";

export default function Home() {
  const [ipaEnabled, setIPAEnabled] = useState(true);
  const [voicesData, setVoicesData] = useState<{
    locale: string,
    short_name: string
  }[] | null>(null);
  const [loading, setLoading] = useState(true);
  const [targetLang, setTargetLang] = useState('Italian');

  const [sourceText, setSourceText] = useState('');
  const [targetText, setTargetText] = useState('');
  const [sourceIPA, setSourceIPA] = useState('');
  const [targetIPA, setTargetIPA] = useState('');
  const [sourceLocale, setSourceLocale] = useState<string | null>(null);
  const [targetLocale, setTargetLocale] = useState<string | null>(null);

  const [translating, setTranslating] = useState(false);
  const { playAudio } = useAudioPlayer();

  useEffect(() => {
    fetch('/list_of_voices.json')
      .then(res => res.json())
      .then(setVoicesData)
      .catch(() => setVoicesData(null))
      .finally(() => setLoading(false));
  }, []);
  if (loading) return <div>加载中...</div>;
  if (!voicesData) return <div>加载失败</div>;

  const tl = ['English', 'Italian', 'Japanese'];

  const inputLanguage = () => {
    const lang = prompt('Input a language.')?.trim();
    if (lang) {
      setTargetLang(lang);
    }
  }

  const translate = () => {
    if (translating) return;
    if (sourceText.length === 0) return;

    setTranslating(true);

    setTargetText('');
    setSourceLocale(null);
    setTargetLocale(null);
    setSourceIPA('');
    setTargetIPA('');

    const params = new URLSearchParams({
      text: sourceText,
      target: targetLang
    })
    fetch(`/api/translate?${params}`)
      .then(res => res.json())
      .then(obj => {
        setSourceLocale(obj.source_locale);
        setTargetLocale(obj.target_locale);
        setTargetText(obj.target_text);

        if (ipaEnabled) {
          const params = new URLSearchParams({
            text: sourceText
          });
          fetch(`/api/ipa?${params}`)
            .then(res => res.json())
            .then(data => {
              setSourceIPA(data.ipa);
            }).catch(e => {
              console.error(e);
              setSourceIPA('');
            })
          const params2 = new URLSearchParams({
            text: obj.target_text
          });
          fetch(`/api/ipa?${params2}`)
            .then(res => res.json())
            .then(data => {
              setTargetIPA(data.ipa);
            }).catch(e => {
              console.error(e);
              setTargetIPA('');
            })
        }
      }).catch(r => {
        console.error(r);
        setSourceLocale('');
        setTargetLocale('');
        setTargetText('');
      }).finally(() => setTranslating(false));
  }

  const handleInputChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
    setSourceText(e.target.value.trim());
    setTargetText('');
    setSourceLocale(null);
    setTargetLocale(null);
    setSourceIPA('');
    setTargetIPA('');
  }

  const readSource = async () => {
    if (sourceText.length === 0) return;

    if (sourceIPA.length === 0 && ipaEnabled) {
      const params = new URLSearchParams({
        text: sourceText
      });
      fetch(`/api/ipa?${params}`)
        .then(res => res.json())
        .then(data => {
          setSourceIPA(data.ipa);
        }).catch(e => {
          console.error(e);
          setSourceIPA('');
        })
    }

    if (!sourceLocale) {
      try {
        const params = new URLSearchParams({
          text: sourceText.slice(0, 30)
        });
        const res = await fetch(`/api/locale?${params}`);
        const info = await res.json();
        setSourceLocale(info.locale);

        const voice = voicesData.find(v => v.locale.startsWith(info.locale));
        if (!voice) {
          return;
        }

        const url = await getTTSAudioUrl(sourceText, voice.short_name);
        await playAudio(url);
        URL.revokeObjectURL(url);
      } catch (e) {
        console.error(e);
        setSourceLocale(null);
        return;
      }
    } else {
      const voice = voicesData.find(v => v.locale.startsWith(sourceLocale!));
      if (!voice) {
        return;
      }

      const url = await getTTSAudioUrl(sourceText, voice.short_name);
      await playAudio(url);
      URL.revokeObjectURL(url);
    }
  }

  const readTarget = async () => {
    if (targetText.length === 0) return;

    if (targetIPA.length === 0 && ipaEnabled) {
      const params = new URLSearchParams({
        text: targetText
      });
      fetch(`/api/ipa?${params}`)
        .then(res => res.json())
        .then(data => {
          setTargetIPA(data.ipa);
        }).catch(e => {
          console.error(e);
          setTargetIPA('');
        })
    }

    const voice = voicesData.find(v => v.locale.startsWith(targetLocale!));
    if (!voice) return;

    const url = await getTTSAudioUrl(targetText, voice.short_name);
    await playAudio(url);
    URL.revokeObjectURL(url);
  }

  return (
    <>
      <div className="w-screen flex flex-col md:flex-row md:justify-between gap-2 p-2">
        <div className="card1 w-full md:w-1/2 flex flex-col-reverse gap-2">
          <div className="textarea1 border-1 border-gray-200 rounded-2xl w-full h-64 p-2">
            <textarea onChange={handleInputChange} className="resize-none h-8/12 w-full focus:outline-0"></textarea>
            <div className="ipa w-full h-2/12 overflow-auto text-gray-600">
              {sourceIPA}
            </div>
            <div className="h-2/12 w-full flex justify-end items-center">
              <IconClick onClick={async () => {
                if (sourceText.length !== 0)
                  await navigator.clipboard.writeText(sourceText);
              }} src={IMAGES.copy_all} alt="copy"></IconClick>
              <IconClick onClick={readSource} src={IMAGES.play_arrow} alt="play"></IconClick>
            </div>
          </div>
          <div className="option1 w-full flex flex-row justify-between items-center">
            <span>detect language</span>
            <Button label="generate ipa" selected={ipaEnabled} onClick={() => setIPAEnabled(!ipaEnabled)}></Button>
          </div>
        </div>
        <div className="card2 w-full md:w-1/2 flex flex-col-reverse gap-2">
          <div className="textarea2 bg-gray-100 rounded-2xl w-full h-64 p-2">
            <div className="h-8/12 w-full">{
              targetText
            }</div>
            <div className="ipa w-full h-2/12 overflow-auto text-gray-600">
              {targetIPA}
            </div>
            <div className="h-2/12 w-full flex justify-end items-center">
              <IconClick onClick={async () => {
                if (targetText.length !== 0)
                  await navigator.clipboard.writeText(targetText);
              }} src={IMAGES.copy_all} alt="copy"></IconClick>
              <IconClick onClick={readTarget} src={IMAGES.play_arrow} alt="play"></IconClick>
            </div>
          </div>
          <div className="option2 w-full flex gap-1 items-center flex-wrap">
            <span>translate into</span>
            <Button onClick={() => { setTargetLang('English') }} label="English" selected={targetLang === 'English'}></Button>
            <Button onClick={() => { setTargetLang('Italian') }} label="Italian" selected={targetLang === 'Italian'}></Button>
            <Button onClick={() => { setTargetLang('Japanese') }} label="Japanese" selected={targetLang === 'Japanese'}></Button>
            <Button onClick={inputLanguage} label={'Other' + (tl.includes(targetLang) ? '' : ': ' + targetLang)} selected={!(tl.includes(targetLang))}></Button>
          </div>
        </div>
      </div>

      <div className="button-area w-screen flex justify-center items-center">
        <button onClick={translate} className={`text-xl font-extrabold border rounded-4xl p-3 border-gray-200 h-16 ${translating ? 'bg-gray-200' : 'bg-white hover:bg-gray-200 hover:cursor-pointer'}`}>
          {translating ? 'translating...' : 'translate'}
        </button>
      </div>
    </>
  );
}
