import { computed, ref, watch } from 'vue'

import {
  REIMBURSEMENT_LIST_PREVIEW_PARAMS,
  extractExpenseClaimItems,
  fetchApprovalExpenseClaims
} from '../services/reimbursements.js'
import { canAccessAppView } from '../utils/accessControl.js'
import { resolvePendingClaimIds } from '../utils/approvalInbox.js'
import { useSystemState } from './useSystemState.js'

const pendingClaimIds = ref([])
const viewedClaimIds = ref([])
let refreshTimer = null

function buildStorageKey(userId) {
  return `x-financial.approval-viewed:${userId}`
}

function loadViewedClaimIds(userId) {
  if (!userId) {
    return []
  }

  try {
    const raw = localStorage.getItem(buildStorageKey(userId))
    const parsed = raw ? JSON.parse(raw) : []
    return Array.isArray(parsed)
      ? parsed.map((item) => String(item || '').trim()).filter(Boolean)
      : []
  } catch {
    return []
  }
}

function saveViewedClaimIds(userId, claimIds) {
  if (!userId) {
    return
  }

  localStorage.setItem(buildStorageKey(userId), JSON.stringify(claimIds))
}

function pruneViewedClaimIds(viewedIds, pendingIds) {
  const pendingSet = new Set(pendingIds)
  return viewedIds.filter((claimId) => pendingSet.has(claimId))
}

function syncPendingState(pendingIds, userId) {
  pendingClaimIds.value = pendingIds
  const pruned = pruneViewedClaimIds(viewedClaimIds.value, pendingIds)
  if (pruned.length !== viewedClaimIds.value.length) {
    viewedClaimIds.value = pruned
    saveViewedClaimIds(userId, pruned)
  }
}

export function useApprovalInbox() {
  const { currentUser } = useSystemState()

  const userKey = computed(() => {
    const user = currentUser.value || {}
    return String(user.username || user.name || 'anonymous').trim() || 'anonymous'
  })

  const unreadCount = computed(() => {
    const viewedSet = new Set(viewedClaimIds.value)
    return pendingClaimIds.value.filter((claimId) => !viewedSet.has(claimId)).length
  })

  const badgeLabel = computed(() => {
    const count = unreadCount.value
    if (count <= 0) {
      return ''
    }

    return count > 99 ? '99+' : String(count)
  })

  function markClaimViewed(claimId) {
    const normalizedId = String(claimId || '').trim()
    if (!normalizedId || !pendingClaimIds.value.includes(normalizedId)) {
      return
    }

    if (viewedClaimIds.value.includes(normalizedId)) {
      return
    }

    const nextViewed = [...viewedClaimIds.value, normalizedId]
    viewedClaimIds.value = nextViewed
    saveViewedClaimIds(userKey.value, nextViewed)
  }

  function syncPendingClaimIds(claimIds) {
    if (!canAccessAppView(currentUser.value, 'approval')) {
      pendingClaimIds.value = []
      return
    }

    const pendingIds = Array.isArray(claimIds)
      ? claimIds.map((item) => String(item || '').trim()).filter(Boolean)
      : []

    syncPendingState(pendingIds, userKey.value)
  }

  async function refreshApprovalInbox() {
    const user = currentUser.value
    if (!user || !canAccessAppView(user, 'approval')) {
      pendingClaimIds.value = []
      return
    }

    try {
      const payload = await fetchApprovalExpenseClaims(REIMBURSEMENT_LIST_PREVIEW_PARAMS)
      syncPendingClaimIds(resolvePendingClaimIds(extractExpenseClaimItems(payload), user))
    } catch {
      pendingClaimIds.value = []
    }
  }

  function startApprovalInboxPolling(intervalMs = 45000) {
    stopApprovalInboxPolling()
    refreshTimer = window.setInterval(() => {
      void refreshApprovalInbox()
    }, intervalMs)
  }

  function stopApprovalInboxPolling() {
    if (refreshTimer) {
      window.clearInterval(refreshTimer)
      refreshTimer = null
    }
  }

  watch(
    userKey,
    (nextUserKey) => {
      viewedClaimIds.value = loadViewedClaimIds(nextUserKey)
      void refreshApprovalInbox()
    },
    { immediate: true }
  )

  return {
    pendingClaimIds,
    unreadCount,
    badgeLabel,
    markClaimViewed,
    syncPendingClaimIds,
    refreshApprovalInbox,
    startApprovalInboxPolling,
    stopApprovalInboxPolling
  }
}
