import { DataService } from "src/app/core/services/data.service";
import { HttpClientService } from "src/app/core/services/http-client.service";
import { CacheService } from "src/app/core/services/cache.service";
import { Observable } from "rxjs";

// ========== Utilitaires de formatage de chaînes ==========
export function lowerFirstLetter(string: string): string {
  if (string.length === 0) return string;
  return string.charAt(0).toLowerCase() + string.slice(1);
}

export function capitalizeFirstLetter(string: string): string {
  if (string.length === 0) return string;
  return string.charAt(0).toUpperCase() + string.slice(1);
}

// ========== Gestion du localStorage ==========
export function setDomaineDDFromLayout(layout: any): void {
  const object = layout.submenu[0];
  const dd = {
    modulename: object.module,
    domaine: object.domaine,
    label: object.label,
  };
  localStorage.setItem("__domaineDD", JSON.stringify(dd));
}

// ========== Gestion des indicateurs de cache ==========
interface CacheIndicators {
  init: boolean;
  isFirst: boolean;
}

function getCacheIndicators(
  initKey: string,
  isFirstKey: string
): CacheIndicators {
  const init = localStorage.getItem(initKey);
  const isFirst = localStorage.getItem(isFirstKey);

  return {
    init: init ? JSON.parse(init) : null,
    isFirst: isFirst ? JSON.parse(isFirst) : null,
  };
}

function shouldCallService(indicators: CacheIndicators): boolean {
  if (indicators.init === null || indicators.isFirst === null) return true;
  return !(indicators.init === true && indicators.isFirst === false);
}

function setCacheFlags(completed: boolean = false): void {
  localStorage.setItem("__initMetadatas", completed ? "false" : "true");
  localStorage.setItem("__initDatas", completed ? "false" : "true");
  localStorage.setItem("isFirst", "false");
}

// ========== Gestion des métadonnées des vues ==========

export async function getListViewElements(
  modulename: string,
  dataService: DataService
): Promise<any> {
  if (!modulename) return [];

  const lvs = localStorage.getItem("__lvs");
  const existingData = lvs ? JSON.parse(lvs) : {};

  // PRIORITÉ 1: Si les métadonnées du module existent déjà en cache, les retourner immédiatement
  if (existingData[modulename]) {
    console.log("✅ Métadonnées du module trouvées dans le cache:", modulename);
    setCacheFlags(true);
    return existingData;
  }

  // PRIORITÉ 2: Vérifier si un appel API est déjà en cours pour ce module
  const callKey = `__metadata_call_${modulename}`;
  if ((window as any)[callKey]) {
    console.log("⏳ Appel API déjà en cours pour:", modulename, "- Attente de la réponse...");
    return await (window as any)[callKey];
  }

  // PRIORITÉ 3: Lancer l'appel API et le stocker pour éviter les doublons
  console.log("🚀 Lancement de l'appel API pour les métadonnées de:", modulename);
  const apiCallPromise = handleListViewCacheUpdate(modulename, dataService, lvs);
  (window as any)[callKey] = apiCallPromise;

  try {
    const result = await apiCallPromise;
    return result;
  } finally {
    delete (window as any)[callKey];
  }
}

async function handleListViewCacheUpdate(
  modulename: string,
  dataService: DataService,
  existingCache: string | null
): Promise<any> {
  const existingData = existingCache ? JSON.parse(existingCache) : {};

  if (existingData[modulename]) {
    console.log("✅ Métadonnées trouvées dans le cache pour:", modulename);
    return existingData;
  }

  try {
    console.log("📡 Appel API pour récupérer les métadonnées de:", modulename);
    setCacheFlags(false); // Set loading state
    const response: any = await dataService.getListViewElements(modulename).toPromise();
    console.log("✅ Métadonnées reçues de l'API pour:", modulename, response);

    // Extraire les données de la réponse API (format: { success, data, message })
    const projects = response?.data || response;
    console.log("📦 Données extraites des métadonnées:", projects);

    const newData = { ...existingData, [modulename]: projects };
    localStorage.setItem("__lvs", JSON.stringify(newData));
    setCacheFlags(true); // Set completed state
    return newData;
  } catch (error) {
    console.error("❌ Erreur lors de la récupération des métadonnées:", error);
    setCacheFlags(true);
    // Retourner un objet avec la structure attendue au lieu d'un array vide
    return existingData;
  }
}

function getFromCache(cache: string | null, modulename: string): any {
  if (!cache) return [];
  const parsedCache = JSON.parse(cache);
  if (parsedCache && parsedCache[modulename]) {
    setCacheFlags(true);
    return parsedCache;
  }
  return [];
}

// ========== Gestion des données générales ==========
export async function getAllDatas(
  domaine: string,
  modulename: string,
  dataService: DataService,
  isFirst: boolean
): Promise<any> {
  if (!modulename) return [];

  // Éviter les appels multiples pour le même module
  const callKey = `${domaine}_${modulename}_${isFirst}`;
  if ((window as any).__activeDataCalls && (window as any).__activeDataCalls.has(callKey)) {
    console.log("⚠️ Appel getAllDatas déjà en cours pour:", callKey);
    return (window as any).__activeDataCalls.get(callKey);
  }

  const indicators = getCacheIndicators("__initDatas", "isFirst");
  const shouldCall = shouldCallService(indicators);

  if (shouldCall) {
    // Marquer l'appel comme en cours
    if (!(window as any).__activeDataCalls) {
      (window as any).__activeDataCalls = new Map();
    }
    
    const promise = handleDataCacheUpdate(
      domaine,
      modulename,
      dataService,
      isFirst
    );
    
    (window as any).__activeDataCalls.set(callKey, promise);
    
    try {
      const result = await promise;
      (window as any).__activeDataCalls.delete(callKey);
      return result;
    } catch (error) {
      (window as any).__activeDataCalls.delete(callKey);
      throw error;
    }
  } else {
    return getFromDataCache(modulename);
  }
}

async function handleDataCacheUpdate(
  domaine: string,
  modulename: string,
  dataService: DataService,
  isFirst: boolean
): Promise<any> {
  const existingCache = localStorage.getItem("__datas");
  const existingData = existingCache ? JSON.parse(existingCache) : {};

  if (existingData[modulename]) {
    console.log("Data already exists in cache for:", modulename);
    return existingData;
  }

  if (!isFirst && !existingCache) {
    console.log("Not first call and no cache exists, returning empty array");
    return [];
  }

  try {
    console.log("Calling getAll for:", { domaine, modulename });
    setCacheFlags(false);
    const apiData = await dataService.getAll(domaine, modulename).toPromise();
    
    console.log("API Response:", apiData);
    
    if (!apiData) {
      console.warn("No data received from API");
      setCacheFlags(true);
      return [];
    }

    // Priorité : data (nouveau format) > records (legacy) > tableau vide
    const newData = { ...existingData, [modulename]: Array.isArray(apiData) ? apiData : (apiData as any)?.data || (apiData as any)?.records || [] };
    localStorage.setItem("__datas", JSON.stringify(newData));
    setCacheFlags(true);
    
    console.log("Data cached successfully for:", modulename);
    return newData;
  } catch (error) {
    console.error("Error fetching all data:", error);
    console.error("Error details:", {
      domaine,
      modulename,
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined
    });
    setCacheFlags(true);
    
    // Retourner les données existantes en cas d'erreur
    const fallbackData = localStorage.getItem("__datas");
    if (fallbackData) {
      console.log("Returning fallback data from cache");
      return JSON.parse(fallbackData);
    }
    
    return [];
  }
}

function getFromDataCache(modulename: string): any {
  const datas = localStorage.getItem("__datas");
  if (!datas) return [];

  const parsedData = JSON.parse(datas);
  if (parsedData && parsedData[modulename]) {
    setCacheFlags(true);
    return parsedData;
  }
  return [];
}

// ========== Gestion des éléments de menu ==========
export async function getAllElements(
  url: string,
  httpClientService: HttpClientService
): Promise<any> {
  const cachedMenus = localStorage.getItem("__menus");

  if (cachedMenus) {
    const parsedMenus = JSON.parse(cachedMenus);
    if (parsedMenus) return parsedMenus;
  }

  try {
    const apiData = await httpClientService.get(url).toPromise();
    const menus = (apiData as any).data;
    localStorage.setItem("__menus", JSON.stringify(menus));
    return menus;
  } catch (error) {
    console.error("Error fetching menu elements:", error);
    return [];
  }
}

// ========== API Data Operations ==========
export async function detailData(
  domaine: string,
  modulename: string,
  id: string,
  dataService: DataService
): Promise<any> {
  return await dataService.getById(domaine, modulename, id).toPromise();
}

export async function addObject(
  domaine: string,
  modulename: string,
  data: any,
  dataService: DataService
): Promise<any> {
  return await dataService.create(domaine, modulename, data).toPromise();
}

export async function updateObject(
  domaine: string,
  modulename: string,
  data: any,
  recordId: string,
  dataService: DataService
): Promise<any> {
  return await dataService.update(domaine, modulename, recordId, data).toPromise();
}

export async function importData(
  data: any,
  dataService: DataService
): Promise<any> {
  try {
    return await dataService.import(data).toPromise();
  } catch (error) {
    console.error("Erreur lors de l'importation des données :", error);
    throw error;
  }
}

// ========== Fonctions utilitaires ==========
function getLocalStorageData(key: string): any {
  const data = localStorage.getItem(key);
  return data ? JSON.parse(data) : null;
}

function getUpdatedFields(oldItem: any, newItem: any): any {
  const updatedFields: any = {};
  Object.keys(newItem).forEach((key) => {
    const newValue = newItem[key];
    const oldValue = oldItem[key];
    if (
      newValue !== oldValue &&
      newValue !== null &&
      newValue !== "" &&
      newValue !== "0000-00-00 00:00:00"
    ) {
      updatedFields[key] = newValue;
    }
  });
  return updatedFields;
}

// ========== Gestion du localStorage pour les données ==========
export function addDataStorage(modulename: string, data: any): void {
  const existingData = getLocalStorageData("__datas");
  if (existingData && existingData[modulename]) {
    existingData[modulename].unshift(data);
    localStorage.setItem("__datas", JSON.stringify(existingData));
    window.location.reload();
  }
}

export function removeDataStorage(
  modulename: string,
  dataToRemove: number[]
): void {
  const existingData = getLocalStorageData("__datas");
  if (existingData && existingData[modulename]) {
    existingData[modulename] = existingData[modulename].filter((item: any) => {
      return !dataToRemove.includes(item.id);
    });
    localStorage.setItem("__datas", JSON.stringify(existingData));
    window.location.reload();
  }
}

export function updateDataStorage(modulename: string, updatedItem: any): void {
  const existingData = getLocalStorageData("__datas");
  if (!existingData || !existingData[modulename]) {
    console.error(`Module ${modulename} introuvable dans le stockage local.`);
    return;
  }

  const dataModule = existingData[modulename];
  const index = dataModule.findIndex((item: any) => item.id === updatedItem.id);

  if (index === -1) {
    console.error("Aucun élément trouvé avec cet ID:", updatedItem.id);
    return;
  }

  const updatedFields = getUpdatedFields(dataModule[index], updatedItem);
  if (Object.keys(updatedFields).length > 0) {
    dataModule[index] = { ...dataModule[index], ...updatedFields };
    localStorage.setItem("__datas", JSON.stringify(existingData));
    window.location.reload();
  }
}
export function massUpdateDataStorage(modulename: string, updatedData: any[]) {
  if (!Array.isArray(updatedData)) {
    console.error(
      "Paramètre 'updatedData' invalide : Ce n'est pas un tableau."
    );
    return;
  }

  let datast = localStorage.getItem("__datas");

  if (datast != null) {
    let __datast = JSON.parse(datast);

    if (__datast[modulename] != undefined) {
      let dataM = __datast[modulename];

      if (!Array.isArray(dataM)) {
        console.error(
          `Les données du module ${modulename} ne sont pas un tableau.`
        );
        return;
      }

      updatedData.forEach((newValues: any) => {
        const id = newValues?.id;
        if (!id) {
          console.warn("L'élément ne contient pas d'ID valide : ", newValues);
          return;
        }

        const index = dataM.findIndex((item: any) => item.id === id);

        if (index !== -1) {
          const oldItem = dataM[index];
          let updatedFields: any = {};

          Object.keys(newValues).forEach((key) => {
            const newValue = newValues[key];
            const oldValue = oldItem[key];

            if (newValue !== oldValue && newValue !== null && newValue !== "") {
              updatedFields[key] = newValue;
            }
          });

          if (Object.keys(updatedFields).length > 0) {
            dataM[index] = {
              ...oldItem,
              ...updatedFields,
            };
          }
        } else {
          console.warn(`ID ${id} introuvable dans ${modulename}`);
        }
      });

      __datast[modulename] = dataM;
      localStorage.setItem("__datas", JSON.stringify(__datast));
      window.location.reload();
    } else {
      console.error(`Module ${modulename} introuvable dans le stockage local.`);
    }
  } else {
    console.error("Aucune donnée trouvée dans le stockage local.");
  }
}

// ========== Gestion des permissions et actions ==========
export function permissionCta(ctas: any, cta: any): boolean {
  const perm = ctas.filter((item: any) => item.action === cta);
  return perm.length > 0;
}

export function ctaName(ctas: any, cta: any): string {
  let name = "";
  const names = ctas.filter((item: any) => item.action === cta);
  if (names.length > 0) {
    name = names[0].label;
  }
  return name;
}
