import { computed, ref } from 'vue'

import type { Listing } from '@/features/listings/api/listings'

const historyKey = 'hfb.listing.view.history'
const favoriteKey = 'hfb.listing.favorites'
const maxHistoryItems = 80

export interface ListingCollectionItem {
  listing: Listing
  viewed_at?: string
  favorited_at?: string
}

const historyItems = ref<ListingCollectionItem[]>(readItems(historyKey))
const favoriteItems = ref<ListingCollectionItem[]>(readItems(favoriteKey))

export function useListingCollections() {
  const history = computed(() => historyItems.value)
  const favorites = computed(() => favoriteItems.value)
  const favoriteIDs = computed(() => new Set(favoriteItems.value.map(item => item.listing.id)))

  function recordListingView(listing: Listing) {
    const nextItem: ListingCollectionItem = {
      listing: snapshotListing(listing),
      viewed_at: new Date().toISOString(),
    }
    historyItems.value = [
      nextItem,
      ...historyItems.value.filter(item => item.listing.id !== listing.id),
    ].slice(0, maxHistoryItems)
    writeItems(historyKey, historyItems.value)
  }

  function isFavorite(listingID: number) {
    return favoriteIDs.value.has(listingID)
  }

  function toggleFavorite(listing: Listing) {
    if (isFavorite(listing.id)) {
      favoriteItems.value = favoriteItems.value.filter(item => item.listing.id !== listing.id)
      writeItems(favoriteKey, favoriteItems.value)
      return false
    }
    favoriteItems.value = [
      {
        listing: snapshotListing(listing),
        favorited_at: new Date().toISOString(),
      },
      ...favoriteItems.value.filter(item => item.listing.id !== listing.id),
    ]
    writeItems(favoriteKey, favoriteItems.value)
    return true
  }

  function removeHistory(listingID: number) {
    historyItems.value = historyItems.value.filter(item => item.listing.id !== listingID)
    writeItems(historyKey, historyItems.value)
  }

  function removeFavorite(listingID: number) {
    favoriteItems.value = favoriteItems.value.filter(item => item.listing.id !== listingID)
    writeItems(favoriteKey, favoriteItems.value)
  }

  function clearHistory() {
    historyItems.value = []
    writeItems(historyKey, historyItems.value)
  }

  return {
    history,
    favorites,
    favoriteIDs,
    recordListingView,
    isFavorite,
    toggleFavorite,
    removeHistory,
    removeFavorite,
    clearHistory,
  }
}

function readItems(key: string): ListingCollectionItem[] {
  if (typeof localStorage === 'undefined') return []
  try {
    const raw = localStorage.getItem(key)
    if (!raw) return []
    const parsed = JSON.parse(raw) as unknown
    if (!Array.isArray(parsed)) return []
    return parsed.map(normalizeItem).filter((item): item is ListingCollectionItem => Boolean(item))
  } catch {
    localStorage.removeItem(key)
    return []
  }
}

function normalizeItem(value: unknown): ListingCollectionItem | null {
  if (!isRecord(value) || !isRecord(value.listing)) return null
  const id = Number(value.listing.id)
  if (!Number.isFinite(id) || id <= 0) return null
  return {
    listing: value.listing as unknown as Listing,
    viewed_at: typeof value.viewed_at === 'string' ? value.viewed_at : undefined,
    favorited_at: typeof value.favorited_at === 'string' ? value.favorited_at : undefined,
  }
}

function writeItems(key: string, items: ListingCollectionItem[]) {
  if (typeof localStorage === 'undefined') return
  localStorage.setItem(key, JSON.stringify(items))
}

function snapshotListing(listing: Listing): Listing {
  return JSON.parse(JSON.stringify(listing)) as Listing
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null
}
