import { defineStore } from 'pinia'
import { ref } from 'vue'
import { waitForHydration } from '@/pinia/Plugin/indexdb'

const cloneJson = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T

export const useKvStore = defineStore('kv', () => {
  const entries = ref<Record<string, unknown>>({})
  const ready = ref(false)
  const loading = ref<Promise<void> | null>(null)
  let hydrationReady = false
  let hydrationTask: Promise<void> | null = null

  const ensureReady = async () => {
    if (ready.value) return
    if (loading.value) {
      await loading.value
      return
    }
    loading.value = (async () => {
      if (!hydrationReady) {
        if (!hydrationTask) {
          hydrationTask = waitForHydration('kv')
            .catch(() => undefined)
            .finally(() => {
              hydrationReady = true
              hydrationTask = null
            })
        }
        await hydrationTask
      }
      ready.value = true
    })()
    await loading.value
    loading.value = null
  }

  const getItem = async <T = unknown>(keyRaw: string | number): Promise<T | null> => {
    await ensureReady()
    const key = String(keyRaw || '').trim()
    if (!key) return null
    if (!Object.prototype.hasOwnProperty.call(entries.value, key)) return null
    return cloneJson(entries.value[key] as T)
  }

  const setItem = async <T = unknown>(keyRaw: string | number, value: T): Promise<void> => {
    await ensureReady()
    const key = String(keyRaw || '').trim()
    if (!key) return
    entries.value[key] = cloneJson(value)
  }

  const removeItem = async (keyRaw: string | number): Promise<void> => {
    await ensureReady()
    const key = String(keyRaw || '').trim()
    if (!key) return
    delete entries.value[key]
  }

  const keys = async (): Promise<string[]> => {
    await ensureReady()
    return Object.keys(entries.value)
  }

  const clear = async (): Promise<void> => {
    await ensureReady()
    entries.value = {}
  }

  const exportEntries = async () => {
    await ensureReady()
    return Object.entries(entries.value).map(([key, value]) => ({ key, value: cloneJson(value) }))
  }

  const importEntries = async (
    incoming: Array<{ key: string; value: unknown }>,
    options?: { replace?: boolean }
  ) => {
    await ensureReady()
    if (options?.replace !== false) {
      entries.value = {}
    }
    for (const item of incoming || []) {
      const key = String(item?.key || '').trim()
      if (!key) continue
      entries.value[key] = cloneJson(item.value)
    }
  }

  return {
    entries,
    ready,
    ensureReady,
    getItem,
    setItem,
    removeItem,
    keys,
    clear,
    exportEntries,
    importEntries
  }
}, {
  persist: true
})
