import type { VueI18n } from 'vue-i18n'
import type { RouteLocation, Router } from 'vue-router'
import type { CookieData, GenericResponse } from '~/types'

// Extend the NuxtApp type
declare module '#app' {
  interface NuxtApp {
    $session: Session
  }
}

declare module 'vue' {
  interface ComponentCustomProperties {
    $session: Session
  }
}

export class Session {
  cookieData = ref({} as CookieData)
  urlParams = new URLSearchParams()
  currentLanguageIso = ref('' as string)
  currentCountryIso = ref('' as string)
  currentCurrencyIso = ref('' as string)

  route = {} as RouteLocation
  router = {} as Router

  i18n = {} as VueI18n
  sessionOngoing: boolean = false

  constructor(i18n: VueI18n, router: Router) {
    this.route = router.currentRoute.value
    this.router = router
    this.i18n = i18n

    this.setLanguage(
      this.route.query?.lang_iso
        ? (this.route.query?.lang_iso as string)
        : unref(i18n.locale),
    )
    this.setCountry(
      this.route.query?.country_iso
        ? (this.route.query?.country_iso as string)
        : '',
    )
    this.setCurrency(
      this.route.query?.currency_iso
        ? (this.route.query?.currency_iso as string)
        : '',
    )
  }

  async loadSession() {
    if (this.sessionOngoing) return
    this.sessionOngoing = true
    this.setQueryParams()
    const { data } = await useMyFetch<GenericResponse<CookieData>>(
      `/api/public/cookie?${this.urlParams.toString()}`,
      {
        headers: {
          'Content-Type': 'application/json',
        },
        onErrorOccured: (_, status) => {
          throw new Error(`HTTP error: ${status}`)
        },
      },
    )
    this.cookieData.value = data
    this.currentCountryIso.value = this.cookieData.value.country.iso_code
    this.currentLanguageIso.value = this.cookieData.value.language.iso_code
    this.currentCurrencyIso.value = this.cookieData.value.currency.iso_code
    setTimeout(() => (this.sessionOngoing = false), 2000)
  }

  setLanguage(iso: string) {
    this.currentLanguageIso.value = iso
  }

  setCurrency(iso: string) {
    this.currentCurrencyIso.value = iso
  }

  setCountry(iso: string) {
    this.currentCountryIso.value = iso
  }

  setQueryParams() {
    if (this.currentLanguageIso.value.length > 0) {
      this.urlParams.set('lang_iso', this.currentLanguageIso.value)
    }
    else {
      this.urlParams.delete('lang_iso')
    }

    if (this.currentCountryIso.value.length > 0) {
      this.urlParams.set('country_iso', this.currentCountryIso.value)
    }
    else {
      this.urlParams.delete('country_iso')
    }

    if (this.currentCurrencyIso.value.length > 0) {
      this.urlParams.set('currency_iso', this.currentCurrencyIso.value)
    }
    else {
      this.urlParams.delete('currency_iso')
    }
  }
}

export default defineNuxtPlugin(async (nuxtApp) => {
  const loaded = [] as Array<string>

  const { $i18n: i18n } = nuxtApp as unknown as { $i18n: VueI18n }
  const { $router: router } = nuxtApp as unknown as { $router: Router }

  i18n.onBeforeLanguageSwitch = async (_, newLocale) => {
    if (loaded.includes(newLocale)) return

    try {
      loaded.push(newLocale)
      const { data } = await useMyFetch<GenericResponse<object>>(
        '/api/public/front/translation',
      )

      i18n.setLocaleMessage(newLocale, data)
    }
    catch (err) {
      console.error('❌ Failed to load translation for locale:', newLocale)
      throw err
    }
  }

  const session = new Session(i18n, router)

  await session.loadSession()
  nuxtApp.provide('session', session)
})
