import { createSharedComposable } from '@vueuse/core'

type ChangelogEntry = {
  hash: string
  shortHash: string
  subject: string
  authorName: string
  committedAt: string
}

type ChangelogSeenState = {
  lastOpenedAt: string | null
  latestSeenHash: string | null
}

const defaultSeenState = (): ChangelogSeenState => ({
  lastOpenedAt: null,
  latestSeenHash: null
})

let changelogRequest: Promise<void> | null = null

const _useChangelog = () => {
  const auth = useAuthStore()

  const entries = useState<ChangelogEntry[]>('changelog:entries', () => [])
  const pending = useState<boolean>('changelog:pending', () => false)
  const error = useState<string | null>('changelog:error', () => null)
  const loadedKey = useState<string | null>('changelog:loaded-key', () => null)
  const seenState = useState<ChangelogSeenState>('changelog:seen-state', defaultSeenState)

  const scopeKey = computed(() => {
    const userId = auth.user?.id
    const tenantId = auth.activeTenant

    if (!userId || !tenantId) return null

    return `${userId}:${tenantId}`
  })

  const storageKey = computed(() => {
    if (!scopeKey.value) return null

    return `fedeo:changelog:last-opened:${scopeKey.value}`
  })

  const latestEntry = computed(() => entries.value[0] || null)

  const hasUnread = computed(() => {
    if (!latestEntry.value?.hash) return false

    return latestEntry.value.hash !== seenState.value.latestSeenHash
  })

  function loadSeenState() {
    if (!process.client || !storageKey.value) {
      seenState.value = defaultSeenState()
      return
    }

    try {
      const raw = localStorage.getItem(storageKey.value)

      if (!raw) {
        seenState.value = defaultSeenState()
        return
      }

      const parsed = JSON.parse(raw)

      seenState.value = {
        lastOpenedAt: parsed?.lastOpenedAt || null,
        latestSeenHash: parsed?.latestSeenHash || null
      }
    } catch (err) {
      console.error('Could not parse changelog seen state', err)
      seenState.value = defaultSeenState()
    }
  }

  async function refresh(force = false) {
    if (!process.client || !scopeKey.value) return
    if (!force && loadedKey.value === scopeKey.value && entries.value.length) return
    if (changelogRequest) return changelogRequest

    changelogRequest = (async () => {
      pending.value = true
      error.value = null

      try {
        const response = await useNuxtApp().$api('/api/functions/changelog', {
          query: { limit: 20 }
        })

        entries.value = Array.isArray(response?.entries) ? response.entries : []
        loadedKey.value = scopeKey.value
      } catch (err: any) {
        error.value = err?.data?.error || err?.message || 'Changelog konnte nicht geladen werden.'
      } finally {
        pending.value = false
      }
    })()

    try {
      await changelogRequest
    } finally {
      changelogRequest = null
    }
  }

  function markAsSeen() {
    if (!process.client || !storageKey.value) return

    const nextState = {
      lastOpenedAt: new Date().toISOString(),
      latestSeenHash: latestEntry.value?.hash || null
    }

    seenState.value = nextState

    try {
      localStorage.setItem(storageKey.value, JSON.stringify(nextState))
    } catch (err) {
      console.error('Could not persist changelog seen state', err)
    }
  }

  watch(storageKey, () => {
    loadSeenState()
  }, { immediate: true })

  watch(scopeKey, (nextScopeKey, previousScopeKey) => {
    if (!process.client || !nextScopeKey) return

    if (nextScopeKey !== previousScopeKey) {
      entries.value = []
      loadedKey.value = null
    }

    void refresh(true)
  }, { immediate: true })

  return {
    entries,
    pending,
    error,
    latestEntry,
    hasUnread,
    seenState,
    refresh,
    markAsSeen
  }
}

export const useChangelog = createSharedComposable(_useChangelog)
