import { db } from "./db";
import axios from "./axiosConfig";

// Global cache for master translations
if (!window.translationCache) {
  window.translationCache = {};
}

const CACHE_DURATION = 60 * 60 * 1000; // 1 hour in milliseconds
const S3_BASE_URL =
  "https://learngual-bucket.sfo3.digitaloceanspaces.com/media/media/";

/**
 * Send translation request to backend (fire-and-forget)
 */
async function sendTranslationRequest(texts, kwargs, language) {
  try {
    axios({
      url: "/iam/v1/utils/translate/",
      method: "POST",
      data: {
        language,
        sentences: texts,
        kwargs,
      },
      params: {
        _account: "",
      },
      authRequired: false,
    });
  } catch (error) {
    // Fire-and-forget, ignore errors
    console.warn("Translation request failed:", error);
  }
}

/**
 * Fetch master translations from S3 with caching
 * Since the JSON contains all languages, we cache it once regardless of language
 */
async function getMasterTranslationsWithCache() {
  const now = Date.now();
  const cached = window.translationCache.master;

  // Check if cache is valid and not expired
  if (cached && cached.data && cached.expires > now) {
    return cached.data;
  }

  try {
    // Fetch from S3 - master JSON contains all languages
    const response = await fetch(
      `${S3_BASE_URL}qFpINMa05DrgUgzO0PEboReejximpq2r3VL2AmFZAwIq6fTN3A.json`
    );

    if (!response.ok) {
      throw new Error(`Failed to fetch translations: ${response.status}`);
    }

    const masterTranslations = await response.json();

    // Cache in memory (single cache for all languages since JSON contains all)
    window.translationCache.master = {
      data: masterTranslations,
      timestamp: now,
      expires: now + CACHE_DURATION,
    };

    console.log(masterTranslations, "master");

    return masterTranslations;
  } catch (error) {
    console.error("Failed to fetch master translations:", error);

    // Fallback to cached data if available (even if expired)
    if (cached && cached.data) {
      return cached.data;
    }

    throw error;
  }
}

/**
 * Extract relevant translations for specific texts
 * Supports multiple languages: ko -> KO, fr -> FR, etc.
 */
function extractRelevantTranslations(masterTranslations, texts, language) {
  const relevantTranslations = {};
  const languageCode = language.toUpperCase(); // ko -> KO, fr -> FR

  texts.forEach((text) => {
    if (masterTranslations[text] && masterTranslations[text][languageCode]) {
      const translation = masterTranslations[text][languageCode];
      // Only use translation if it's not empty
      relevantTranslations[text] = translation.trim() || text;
    } else {
      // Return original text if translation not found
      relevantTranslations[text] = text;
    }
  });

  return relevantTranslations;
}

/**
 * Cache screen-specific translations in IndexedDB
 */
async function cacheScreenTranslations(translations, screenId, language) {
  try {
    const translationEntries = Object.keys(translations).map((key) => ({
      key,
      value: translations[key],
      screenId,
      updatedAt: new Date().toDateString(),
    }));

    await db[language].bulkPut(translationEntries);
  } catch (error) {
    console.error("Failed to cache translations:", error);
  }
}

/**
 * Get cached translations from IndexedDB as fallback
 */
async function getCachedTranslations(screenId, language) {
  try {
    const cached = await db[language].where({ screenId }).toArray();
    return cached.reduce((acc, item) => {
      acc[item.key] = item.value;
      return acc;
    }, {});
  } catch (error) {
    console.error("Failed to get cached translations:", error);
    return {};
  }
}

async function loadTranslations(language = "ko") {
  await new Promise((resolve) => {
    //check if loading else resolve
    if (document.readyState === "complete") {
      return resolve();
    }
    window.addEventListener("load", resolve);
  });

  const screenId = btoa(window.location.href);

  /**
   * @typedef {{text: string; screenId: string; updatedAt: string}} WORDS
   * @type {WORDS[]}
   */
  const words = await db.words.where({ screenId }).toArray();
  const texts = words.map((x) => x.text); // list of texts

  /**
   * @typedef {{ key: string; value: string; screenId: string }} Kwarg
   * @type {Kwarg[]} kwargList
   */
  const kwargList = await db.kwarg.where({ screenId }).toArray();
  const kwargs = kwargList.reduce((x, t) => ({ ...x, [t.key]: t.value }), {});

  // Step 1: Fire-and-forget translation request to backend
  sendTranslationRequest(texts, kwargs, language);

  try {
    // Step 2: Get master translations (cached or fresh from S3)
    const masterTranslations = await getMasterTranslationsWithCache();

    // Step 3: Extract only the translations we need
    const relevantTranslations = extractRelevantTranslations(
      masterTranslations,
      texts,
      language
    );

    // Step 4: Cache the extracted translations in IndexedDB
    await cacheScreenTranslations(relevantTranslations, screenId, language);

    return relevantTranslations;
  } catch (error) {
    console.error("Failed to load translations:", error);

    // Step 5: Fallback to cached translations from IndexedDB
    const cachedTranslations = await getCachedTranslations(screenId, language);

    // If we have cached translations, return them
    if (Object.keys(cachedTranslations).length > 0) {
      return cachedTranslations;
    }

    // Last resort: return original texts
    return texts.reduce((acc, text) => {
      acc[text] = text;
      return acc;
    }, {});
  }
}

export function extractBracedText(text) {
  const pattern = /\{([^}]+)\}/g; // Match all occurrences of text within {}
  const matches = text.match(pattern);
  return matches ? matches.map((match) => match.slice(1, -1)) : []; // Remove braces
}

export default loadTranslations;
