/**
 * Dictionary cache store (client-side).
 */

import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { getDictionary, batchGetDictionaries } from '@/api/dictionary/query'

const DEFAULT_TTL_MS = 30 * 60 * 1000

export const useDictionaryCacheStore = defineStore(
  'dictionaryCacheStore',
  () => {
    const cache = ref<Record<string, Api.Dictionary.DictionaryItemDto[]>>({})
    const expiryMap = ref<Record<string, number>>({})
    const loading = ref(false)

    const normalizeCode = (code: string) => code.trim().toLowerCase()

    const isExpired = (code: string) => {
      const key = normalizeCode(code)
      const expiry = expiryMap.value[key]
      return !expiry || Date.now() > expiry
    }

    const isCached = (code: string) => {
      const key = normalizeCode(code)
      return Array.isArray(cache.value[key]) && !isExpired(key)
    }

    const setCache = (
      code: string,
      items: Api.Dictionary.DictionaryItemDto[],
      ttl = DEFAULT_TTL_MS
    ) => {
      const key = normalizeCode(code)
      cache.value[key] = items
      expiryMap.value[key] = Date.now() + ttl
    }

    const invalidate = (code: string) => {
      const key = normalizeCode(code)
      delete cache.value[key]
      delete expiryMap.value[key]
    }

    const invalidateAll = () => {
      cache.value = {}
      expiryMap.value = {}
    }

    const getDictionaryAction = async (code: string, forceRefresh = false) => {
      const key = normalizeCode(code)
      if (!forceRefresh && isCached(key)) {
        return cache.value[key]
      }

      loading.value = true
      try {
        const result = await getDictionary(code)
        setCache(code, result)
        return result
      } finally {
        loading.value = false
      }
    }

    const batchGetDictionariesAction = async (codes: string[]) => {
      if (!codes.length) return {}

      const cachedResult: Record<string, Api.Dictionary.DictionaryItemDto[]> = {}
      const missing: string[] = []

      codes.forEach((code) => {
        const normalized = normalizeCode(code)
        if (isCached(normalized)) {
          cachedResult[code] = cache.value[normalized]
        } else {
          missing.push(code)
        }
      })

      if (!missing.length) {
        return cachedResult
      }

      loading.value = true
      try {
        const fetched = await batchGetDictionaries(missing)
        Object.keys(fetched).forEach((code) => {
          setCache(code, fetched[code])
          cachedResult[code] = fetched[code]
        })
        return cachedResult
      } finally {
        loading.value = false
      }
    }

    const cacheSize = computed(() => Object.keys(cache.value).length)

    return {
      cache,
      expiryMap,
      loading,
      cacheSize,
      isCached,
      isExpired,
      getDictionary: getDictionaryAction,
      batchGetDictionaries: batchGetDictionariesAction,
      invalidate,
      invalidateAll
    }
  },
  {
    persist: {
      pick: ['cache', 'expiryMap']
    }
  }
)
