// Import necessary packages
import React, { useState, useEffect } from "react";
import { View, Text, TextInput, StyleSheet, Pressable } from "react-native"; // Add Picker import
import { getDb } from "@/app/lib/db";
import { Settings } from "@/app/lib/settings";
import { LanguageServer, fetchWithTimeout } from "@/app/i18n/api";
import { Picker } from "@react-native-picker/picker";
import { longLang } from "@/app/i18n/lang";
import FileSystem, { DownloadResumable } from "expo-file-system";
import { LIBRETRANSLATE_BASE_URL } from "@/constants/api";
import {
  WHISPER_MODELS,
  WHISPER_MODEL_DIR,
  initiateWhisperDownload,
  download_status,
  getWhisperDownloadStatus,
  getWhisperTarget,
  whisper_model_tag_t,
} from "@/app/lib/whisper";
import { File, Paths } from "expo-file-system/next";

type Language = {
  code: string;
  name: string;
};

type LanguageMatrix = {
  [key: string]: Language;
};

type connection_test_t =
  | {
    success: true;
  }
  | {
    success: false;
    error: string;
  };

const SettingsComponent: React.FC = () => {
  const [hostLanguage, setHostLanguage] = useState<string | null>(null);
  const [libretranslateBaseUrl, setLibretranslateBaseUrl] = useState<
    string | null
  >(null);
  const [languages, setLanguages] = useState<undefined | LanguageMatrix>();
  const [isLoaded, setIsLoaded] = useState<boolean>(false);
  const [whisperModel, setWhisperModel] = useState<
    undefined | whisper_model_tag_t
  >();
  const [downloadStatus, setDownloadStatus] = useState<
    undefined | download_status
  >();

  const [langServerConn, setLangServerConn] = useState<
    undefined | connection_test_t
  >();
  const [whisperDownloadProgress, setWhisperDownloadProgress] = useState<
    FileSystem.DownloadProgressData | undefined
  >();
  const [downloader, setDownloader] = useState<DownloadResumable | undefined>();
  const [whisperModelTarget, setWhisperModelTarget] = useState<File | undefined>()

  const fillHostLanguageOptions = async () => {
    const settings = await Settings.getDefault();
    const hostLang = await settings.getHostLanguage();
    setHostLanguage(hostLang || "en");
    const langServer = new LanguageServer(
      libretranslateBaseUrl || LIBRETRANSLATE_BASE_URL
    );
    // Fetch languages from API
    try {
      const langData = await langServer.fetchLanguages();
      setLanguages(langData);
      setLangServerConn({ success: true });
    } catch (err) {
      console.warn("Got an error fetching: %s", err);
      setLangServerConn({
        success: false,
        error: `Could not connect to ${libretranslateBaseUrl}: ${err}`,
      });
    }
  };

  useEffect(() => {
    (async () => {
      // Fetch the database connection
      // const db = await getDb("down");
      const settings = await Settings.getDefault();

      await fillHostLanguageOptions();

      console.log("Fetched settings");

      // Get the current settings values
      const libretranslateUrl =
        (await settings.getLibretranslateBaseUrl()) || LIBRETRANSLATE_BASE_URL;
      setLibretranslateBaseUrl(libretranslateUrl);
      console.log("libretranslate url = %s", libretranslateUrl);
      try {
        const wModel = await settings.getWhisperModel() || "small";
        setWhisperModel(wModel);
        setWhisperModelTarget(new File(WHISPER_MODELS[wModel].target))
      } catch (err) {
        console.warn("Could not set whisper model: %s", err);
      }

      // setWhisperModel(wModel);
      setIsLoaded(true);
      //   console.log("Set is loaded: %s", isLoaded);
    })();

    // Check for whether a model is currently downloading and set the status.
    setInterval(async () => {
      if (!whisperModel) return null;
      const dlStatus = await getWhisperDownloadStatus(whisperModel);
      setDownloadStatus(dlStatus);
      setWhisperModelTarget(new File(WHISPER_MODELS[whisperModel].target))
      console.log("Setting whisper model target to %s", whisperModelTarget);
    }, 1000);

    setInterval(async () => {
      if (!libretranslateBaseUrl) return;
      try {
        const resp = await fetchWithTimeout(
          libretranslateBaseUrl + "/languages",
          {
            method: "HEAD",
            headers: {
              Accept: "application/json",
              "Content-Type": "application/json",
            },
          },
          5000
        );
        if (resp.status !== 200) {
          throw new Error(resp.statusText);
        }
        setLangServerConn({ success: true });
      } catch (err) {
        setLangServerConn({
          success: false,
          error: `Could not connect to ${libretranslateBaseUrl}: ${err}`,
        });
      }
    }, 1000);

    setInterval(async () => {
      const settings = await Settings.getDefault();
      await settings.setHostLanguage(hostLanguage || "en");
      await settings.setLibretranslateBaseUrl(
        libretranslateBaseUrl || LIBRETRANSLATE_BASE_URL
      );
      await settings.setWhisperModel(whisperModel || "small");
    }, 1000);
  }, []);

  const fileExists = async (file: File) => {
    const info = await FileSystem.getInfoAsync(file.uri);
    return info.exists;
  }

  const doDelete = async () => {
    if (!whisperModelTarget) return;
    whisperModelTarget.delete();
  }

  const doReadownload = async () => {
    if (!whisperModel) return;
    await initiateWhisperDownload(whisperModel, {
      force_redownload: true,
      onDownload: setWhisperDownloadProgress,
    });
  };

  const doDownload = async () => {
    if (!whisperModel) return;
    try {
      setDownloader(
        await initiateWhisperDownload(whisperModel, {
          onDownload: setWhisperDownloadProgress,
          force_redownload: true,
        })
      );
      await downloader?.downloadAsync();
      console.log("completed download");
    } catch (err) {
      console.error(err);
    }
  };

  const handleHostLanguageChange = async (value: string) => {
    setHostLanguage(value);

    // Fetch the database connection
    const db = await getDb();
    const settings = new Settings(db);

    // Save the updated setting value
    await settings.setHostLanguage(value);
  };

  const handleLibretranslateBaseUrlChange = async (value: string) => {
    setLibretranslateBaseUrl(value);

    const settings = await Settings.getDefault();

    // Save the updated setting value
    await settings.setLibretranslateBaseUrl(value);

    await fillHostLanguageOptions();
  };

  const handleWhisperModelChange = async (value: string) => {
    const settings = await Settings.getDefault();
    setWhisperModel(value);
    await settings.setWhisperModel(value);
    setWhisperModelTarget(getWhisperTarget(value));
  }

  const doStopDownload = async () => {
    if (!downloader) return;
    await downloader.pauseAsync()
  }

  return isLoaded ? (
    <View style={styles.container}>
      <Text style={styles.label}>Host Language:</Text>
      <Picker
        selectedValue={hostLanguage || ""}
        style={{ height: 50, width: "100%" }}
        onValueChange={handleHostLanguageChange}
        accessibilityHint="hostLanguage"
      >
        {languages &&
          Object.entries(languages).map((lang) => (
            <Picker.Item key={lang[0]} label={lang[1].name} value={lang[0]} />
          ))}
      </Picker>

      <Text style={styles.label}>LibreTranslate Base URL:</Text>
      <TextInput
        style={styles.input}
        value={libretranslateBaseUrl || LIBRETRANSLATE_BASE_URL}
        onChangeText={handleLibretranslateBaseUrlChange}
        accessibilityHint="libretranslate base url"
      />
      {langServerConn &&
        (langServerConn.success ? (
          <Text>Success connecting to {libretranslateBaseUrl}</Text>
        ) : (
          <Text>
            Error connecting to {libretranslateBaseUrl}: {langServerConn.error}
          </Text>
        ))}
      <Picker
        selectedValue={whisperModel || "small"}
        style={{ height: 50, width: "100%" }}
        onValueChange={handleWhisperModelChange}
        accessibilityHint="language"
      >
        {Object.entries(WHISPER_MODELS).map(([key, { label }]) => (
          <Picker.Item key={key} label={label} value={key} />
        ))}
      </Picker>
      <View>
        { /* If there's a downloader, that means we're in the middle of a download */}
        {downloader && whisperDownloadProgress && (
          <Text>
            {whisperDownloadProgress.totalBytesWritten} bytes of {whisperDownloadProgress.totalBytesExpectedToWrite} bytes 

            ({Math.round((whisperDownloadProgress.totalBytesWritten / whisperDownloadProgress.totalBytesExpectedToWrite) * 100)} %)
          </Text>
        )
        }
        <View style={styles.downloadButtonWrapper}>
          {downloader && whisperDownloadProgress && (whisperDownloadProgress.totalBytesWritten !== whisperDownloadProgress.totalBytesExpectedToWrite) ? (
            (<Pressable onPress={doStopDownload} style={styles.pauseDownloadButton}>
              <Text style={styles.buttonText}>Pause Download</Text>
            </Pressable>)
          ) :
            (<Pressable onPress={doDownload} style={styles.downloadButton}>
              <Text style={styles.buttonText}>Download</Text>
            </Pressable>)
          }
          {whisperModelTarget && fileExists(whisperModelTarget) &&
            (<Pressable onPress={doDelete} style={styles.deleteButton}>
              <Text style={styles.buttonText}>Delete</Text>
            </Pressable>)
          }
        </View>
      </View>
    </View>
  ) : (
    <View>
      <Text>Loading ...</Text>
    </View>
  );
};

// Create styles for the component
const styles = StyleSheet.create({
  downloadButtonWrapper: {
    flex: 1,
    flexDirection: "row",
    alignItems: "center",
    verticalAlign: "middle",
  },
  downloadButton: {
    backgroundColor: "blue",
    padding: 10,
    margin: 10,
  },
  deleteButton: {
    backgroundColor: "darkred",
    padding: 10,
    margin: 10,
  },
  pauseDownloadButton: {
    backgroundColor: "#444444",
    padding: 10,
    margin: 10,
  },
  buttonText: {
    color: "white",
    alignSelf: "center",
  },
  container: {
    flex: 1,
    padding: 20,
  },
  label: {
    fontSize: 16,
    marginBottom: 8,
  },
  input: {
    height: 40,
    borderColor: "gray",
    borderWidth: 1,
    marginBottom: 20,
    paddingHorizontal: 8,
  },
});

export default SettingsComponent;
