import { useGlobalStore } from '@store/globalStore'
import { useUserStore } from '@store/UserStore'

export * from './ApiTypes'
import axios from 'axios'

export { addAuthHeaders, API_URL } from './Instance'
// import {AlgoliaSearch} from './AlgoliaController'
import Paths from '@paths'
import { tools } from '@src/store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'

import { serv_constants } from '@src/store/Modules/serv_constants'

import type * as Types from '@src/store/Api/ApiTypes'
import { costanti } from '@src/store/Modules/costanti'
import * as ApiTables from '@src/store/Modules/ApiTables'
import sendRequest from './Inst-Pao'
import Request from './Instance'
import globalroutines from '../../globalroutines/index'
import { useRouter } from 'vue-router'

function ReceiveResponsefromServer(tablesync: string, nametab: string, method: string, risdata: any) {
  // console.log('ReceiveResponsefromServer', nametab, method, risdata)
  if (risdata) {
    // Updated somw data after Server arrived data.
    if (method === 'PATCH') {
      if (nametab === 'projects') {
        if (risdata.projectris) {
          const copyrec = tools.jsonCopy(risdata.projectris)
          // +*Todo conv: Projects.updateProject({ objproj: copyrec })
        }
      }
    }
  }
}

// const algoliaApi = new AlgoliaSearch()
export const Api = {
  async post(path: string, payload?: any, responsedata?: any, options?: any) {
    const globalStore = useGlobalStore()
    globalStore.connData.downloading_server = 1
    globalStore.connData.uploading_server = 1
    return await Request('post', path, payload, responsedata, options)
  },

  async postFormData(path: string, payload?: any, responsedata?: any) {
    const globalStore = useGlobalStore()
    globalStore.connData.uploading_server = 1
    globalStore.connData.downloading_server = 1
    return await Request('postFormData', path, payload, responsedata)
  },

  async get(path: string, payload?: any, responsedata?: any) {
    const globalStore = useGlobalStore()
    globalStore.connData.downloading_server = 1
    globalStore.connData.uploading_server = 0
    return await Request('get', path, payload, responsedata)
  },

  async put(path: string, payload?: any, responsedata?: any) {
    const globalStore = useGlobalStore()
    globalStore.connData.uploading_server = 1
    return await Request('put', path, payload, responsedata)
  },

  async patch(path: string, payload?: any, responsedata?: any) {
    const globalStore = useGlobalStore()
    globalStore.connData.uploading_server = 1
    return await Request('patch', path, payload, responsedata)
  },

  async Delete(path: string, payload: any, responsedata?: any) {
    const globalStore = useGlobalStore()
    globalStore.connData.uploading_server = 1
    return await Request('delete', path, payload, responsedata)
  },

  async checkSession({ token, refresh_token }: any) {
    return await axios.post(import.meta.env.VITE_API_URL + Paths.TOKEN_REFRESH, {
      refresh_token,
    }, {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
  },

  async refreshToken() {
    const userStore = useUserStore();
    try {
      const refrTok = localStorage.getItem(toolsext.localStorage.refreshToken);

      if (!refrTok || refrTok === 'undefined') {
        //throw new Error('Refresh token non disponibile');
        return false;
      }

      const response = await sendRequest('/users/newtok', 'POST', { refreshToken: refrTok });

      if (response && response.data) {
        // Salva il nuovo access token
        localStorage.setItem(toolsext.localStorage.token, response.data.token);

        // Aggiorna il refresh token se fornito dal server
        if (response.data.refreshToken) {
          userStore.setRefreshToken(response.data.refreshToken);
          localStorage.setItem(toolsext.localStorage.refreshToken, response.data.refreshToken);
        }

        return response.data.token;
      } else {
        throw new Error('Risposta del server non valida durante il refresh token');
      }
    } catch (error) {
      console.error('Errore durante il refresh token:', error);
      // Logout dell'utente in caso di errore critico
      // userStore.setAuth('', '');
      // localStorage.removeItem(toolsext.localStorage.token);
      // localStorage.removeItem(toolsext.localStorage.refreshToken);
      throw error;
    }
  },

  async checkTokenScaduto(status, evitaloop, url, method, mydata, setAuthToken = false) {
    const userStore = useUserStore();

    if (status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_TOKEN_EXPIRED) {
      try {
        console.log('Token scaduto. Tentativo di refresh...');
        const newAccessToken = await this.refreshToken();

        if (newAccessToken) {
          userStore.setAuth(newAccessToken, userStore.refreshToken);

          if (!evitaloop) {
            console.log('Nuovo token ottenuto. Riprovo la richiesta...');
            return await this.SendReq(url, method, mydata, setAuthToken, true);
          }
        } else {
          // Se il refresh token fallisce, logout dell'utente
          // userStore.setAuth('', '');
          const $router = useRouter()
          throw { code: toolsext.ERR_RETRY_LOGIN };
        }
      } catch (err2) {
        console.error('Errore durante il refresh token:', err2);

        let mystatus = err2?.code || err2?.status

        if (mystatus === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN || mystatus === toolsext.ERR_RETRY_LOGIN) {
          userStore.setServerCode(toolsext.ERR_AUTHENTICATION);
          userStore.setAuth('', '');
          throw { status: toolsext.ERR_RETRY_LOGIN };
        }

        // Gestione di altri errori critici
        throw err2 || {status: serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN} ;
      }
    } else if (status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN) {
      userStore.setAuth('', '');
      const $router = useRouter()
      throw { status: toolsext.ERR_RETRY_LOGIN };
    }

    return null;
  },

  // Base per la chiamata con gestione degli errori e retry
  async SendReqBase(url, method, mydata, setAuthToken = false, evitaloop = false, myformdata, responsedata, options) {
    const mydataout = {
      ...mydata,
      keyappid: import.meta.env.VITE_PAO_APP_ID,
      idapp: tools.getEnv('VITE_APP_ID'),
    };

    const userStore = useUserStore();
    const globalStore = useGlobalStore();
    userStore.setServerCode(tools.EMPTY);
    userStore.setResStatus(0);

    try {
      const res = await sendRequest(url, method, mydataout, myformdata, responsedata, options);

      // Aggiornamento dello stato della connessione dopo 1 secondo
      setTimeout(() => {
        if (method.toLowerCase() === 'get') {
          globalStore.connData.downloading_server = 0;
        } else {
          globalStore.connData.uploading_server = 0;
          globalStore.connData.downloading_server = 0;
        }
      }, 1000);

      if (res.status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN) {
        userStore.setServerCode(toolsext.ERR_AUTHENTICATION);
        userStore.setAuth('', '');
        throw { code: toolsext.ERR_AUTHENTICATION };
      }

      // Verifica sul token (funzione custom)
      const ret = await this.checkTokenScaduto(res.status, evitaloop, url, method, mydata, setAuthToken);
      if (ret) return ret;

      if (tools.isDebug()) console.log('   ----> ', res);
      return res;
    } catch (error) {
      setTimeout(() => {
        if (method.toLowerCase() === 'get') {
          globalStore.connData.downloading_server = -1;
        } else {
          globalStore.connData.uploading_server = -1;
          globalStore.connData.downloading_server = -1;
        }
      }, 1000);

      const ret = await this.checkTokenScaduto(error.status, evitaloop, url, method, mydataout, setAuthToken);
      if (ret) return ret;

      console.error('Errore nella richiesta:', error);
      throw error;
    }
  },

  /**
 * Creates a Promise that resolves after a specified number of milliseconds.
 * Useful for creating delayed operations or pause in async functions.
 *
 * @param ms - The number of milliseconds to delay
 * @returns A Promise that resolves after the specified delay
 *
 * @example
 * // Basic usage
 * await delay(1000); // waits for 1 second
 *
 * @example
 * // Usage in an async function
 * async function example() {
 *   console.log('Start');
 *   await delay(2000);
 *   console.log('2 seconds later');
 * }
 *
 * @example
 * // Usage with Promise chaining
 * delay(1000).then(() => console.log('1 second passed'));
 */
  async delay(ms: number): Promise<void> {
    // Input validation
    if (ms < 0) {
      throw new Error('Delay time cannot be negative');
    }

    return new Promise(resolve => setTimeout(resolve, ms));
  },

  // Funzione che gestisce la chiamata con retry
  async SendReq(url, method, mydata, setAuthToken = false, evitaloop = false, retryCount = 1, retryDelay = 5000, myformdata = null, responsedata = null, options = null) {
    try {
      return await this.SendReqBase(url, method, mydata, setAuthToken, evitaloop, myformdata, responsedata, options);
    } catch (error) {
      // Se lo status non è 403 e sono rimasti tentativi, eseguo il retry
      const riprova = error.status !== 403 && error.status !== toolsext.ERR_RETRY_LOGIN;
      if (retryCount > 0 && riprova) {
        console.log(`❌❌❌ Retrying request. Attempts remaining: ${retryCount}`);
        await this.delay(retryDelay);
        return this.SendReq(url, method, mydata, setAuthToken, evitaloop, retryCount - 1, retryDelay, myformdata, responsedata);
      }
      throw error;
    }
  },

  async syncAlternative(mystrparam: string) {
    console.log('[ALTERNATIVE Background syncing', mystrparam)

    const multiparams = mystrparam.split('|')
    if (multiparams) {
      if (multiparams.length > 3) {
        const cmd = multiparams[0]
        const tablesync = multiparams[1]
        const nametab = multiparams[2]
        const method = multiparams[3]
        // const token = multiparams[3]

        if (cmd === ApiTables.DB.CMD_SYNC) {
          let errorfromserver = false
          let lettoqualcosa = false

          // console.log('A1) INIZIO.............................................................')
          return globalroutines('readall', tablesync, null)
            .then((alldata) => {
              if (alldata === undefined) {
                console.log('alldata NON DEFINITA')
                return true
              }
              const myrecs = [...alldata]

              const promises = myrecs.map((rec) => {
                let link = `/${ApiTables.getLinkByTableName(nametab)}`

                if (method !== 'POST') {
                  link += `/${rec._id}`
                }

                console.log('----------------------- LEGGO QUALCOSA ', link)

                // Insert/Delete/Update table to the server
                return this.SendReq(link, method, rec)
                  .then((ris) => {
                    ReceiveResponsefromServer(tablesync, nametab, method, ris.data)
                    lettoqualcosa = true
                    return globalroutines('delete', tablesync, null, rec._id)
                  })
                  .then(() => {
                    return globalroutines('delete', 'swmsg', null, mystrparam)
                  }).catch((err) => {
                    if (err.msgerr) {
                      if (err.msgerr.message.includes('Failed to fetch') || err.msgerr.message.includes('Network Error')) {
                        errorfromserver = true
                      }
                    }
                    console.log(' [Alternative] !!!!!!!!!!!!!!!   Error while sending data', err, errorfromserver, 'lettoqualcosa', lettoqualcosa)
                    if (!errorfromserver) {
                      return globalroutines('delete', 'swmsg', null, mystrparam)
                    }
                  })
              })

              // CALL ALL THE PROMISES
              return Promise.all(promises).then(() => (errorfromserver && !lettoqualcosa)).catch((err) => (errorfromserver && !lettoqualcosa))
            }).catch((error) => {
              console.log('¨¨¨¨¨¨¨¨¨¨¨¨¨¨  errorfromserver:', errorfromserver, error)
              return (errorfromserver && !lettoqualcosa)
            })
            .then((error) => {
              const mystate = (error || errorfromserver) ? 'offline' : 'online'

              const globalStore = useGlobalStore()
              globalStore.setStateConnection(mystate)
              globalStore.saveConfig({ _id: costanti.CONFIG_ID_STATE_CONN, value: mystate })
            })
        }
      }
    }
    return null
  },
}
