import { create } from 'zustand'
import { persist } from 'zustand/middleware'

/**
 * Per-item personal annotations the user makes outside of Jellyfin's
 * binary watched/favorite flags: a freeform note, a 1-10 rating, and a
 * rewatch counter (with a flag for whether the most-recent watch was a
 * first-time vs rewatch). Persisted locally - none of this data
 * round-trips to the Jellyfin server today.
 *
 * Keys are Jellyfin item ids. We never write entries for synthetic
 * `tmdb-...` ids since those don't have stable identity across user
 * libraries; the UI guards against that at the call site.
 */

export interface PersonalEntry {
  /** 0 = unrated; 1-10 otherwise. */
  rating: number
  note: string
  /** Total times the user has played this item to completion or near-it. */
  rewatchCount: number
  /** Tracks whether the most-recent watch was logged as a rewatch. Used by
   *  the diary stats and surface UIs to avoid double-counting. */
  lastWasRewatch: boolean
  /** Updated every time we touch any field, for sort-by-recent. */
  updatedAt: string
}

const EMPTY: PersonalEntry = {
  rating: 0,
  note: '',
  rewatchCount: 0,
  lastWasRewatch: false,
  updatedAt: '',
}

interface State {
  entries: Record<string, PersonalEntry>
  setRating: (itemId: string, rating: number) => void
  setNote: (itemId: string, note: string) => void
  recordWatch: (itemId: string, asRewatch: boolean) => void
  /** Increment rewatch count silently - used by the auto-tracker when an
   *  already-watched item starts playback again. */
  incrementRewatch: (itemId: string) => void
  clear: (itemId: string) => void
}

function ensure(entries: Record<string, PersonalEntry>, id: string): PersonalEntry {
  return entries[id] || { ...EMPTY }
}

export const usePersonalData = create<State>()(
  persist(
    (set, get) => ({
      entries: {},
      setRating: (itemId, rating) =>
        set(s => ({
          entries: {
            ...s.entries,
            [itemId]: {
              ...ensure(s.entries, itemId),
              rating: Math.max(0, Math.min(10, Math.round(rating))),
              updatedAt: new Date().toISOString(),
            },
          },
        })),
      setNote: (itemId, note) =>
        set(s => ({
          entries: {
            ...s.entries,
            [itemId]: {
              ...ensure(s.entries, itemId),
              note,
              updatedAt: new Date().toISOString(),
            },
          },
        })),
      recordWatch: (itemId, asRewatch) =>
        set(s => {
          const cur = ensure(s.entries, itemId)
          return {
            entries: {
              ...s.entries,
              [itemId]: {
                ...cur,
                rewatchCount: asRewatch ? cur.rewatchCount + 1 : cur.rewatchCount,
                lastWasRewatch: asRewatch,
                updatedAt: new Date().toISOString(),
              },
            },
          }
        }),
      incrementRewatch: itemId => {
        const s = get()
        const cur = ensure(s.entries, itemId)
        // Per-mount dedup is the caller's responsibility (PlayerPage
        // tracks the last item it incremented in a ref). The store
        // unconditionally bumps so a user who closes and reopens the
        // app to rewatch the same title actually sees the count rise.
        set({
          entries: {
            ...s.entries,
            [itemId]: {
              ...cur,
              rewatchCount: cur.rewatchCount + 1,
              lastWasRewatch: true,
              updatedAt: new Date().toISOString(),
            },
          },
        })
      },
      clear: itemId =>
        set(s => {
          const next = { ...s.entries }
          delete next[itemId]
          return { entries: next }
        }),
    }),
    { name: 'personal-data-v1' },
  ),
)

export function getPersonalEntry(itemId: string | null | undefined): PersonalEntry {
  if (!itemId) return EMPTY
  return usePersonalData.getState().entries[itemId] || EMPTY
}
