import type { BaseItemDto } from '../api/types'

/**
 * Heavier stats derivations used by /stats. Profile-page helpers live in
 * `watch-stats.ts` (streaks, basic genre share, longest binge); these
 * add hours-weighted breakdowns, completion ratios, studios, and the
 * cross-series "time saved by skipping" rollup.
 */

const TICKS_PER_HOUR = 36_000_000_000
const KEY_PREFIX = 'jf_time_saved_'

export interface HoursShare {
  label: string
  hours: number
  share: number
}

export interface CompletionStats {
  total: number
  completed: number
  inProgress: number
  unstarted: number
  completionRate: number
}

export interface PersonShare {
  name: string
  /** Number of items this person appears in. */
  count: number
}

export function hoursPerGenre(items: BaseItemDto[]): HoursShare[] {
  const buckets = new Map<string, number>()
  let total = 0
  for (const it of items) {
    const ticks = Number(it.RunTimeTicks ?? 0)
    if (!ticks) continue
    const hours = ticks / TICKS_PER_HOUR
    const genres = it.Genres || []
    if (genres.length === 0) continue
    for (const g of genres) {
      buckets.set(g, (buckets.get(g) || 0) + hours)
      total += hours
    }
  }
  if (total === 0) return []
  return [...buckets.entries()]
    .map(([label, hours]) => ({ label, hours, share: hours / total }))
    .sort((a, b) => b.hours - a.hours)
}

export function hoursPerStudio(items: BaseItemDto[]): HoursShare[] {
  const buckets = new Map<string, number>()
  let total = 0
  for (const it of items) {
    const ticks = Number(it.RunTimeTicks ?? 0)
    if (!ticks) continue
    const hours = ticks / TICKS_PER_HOUR
    const studios = (it.Studios || []).map(s => s.Name).filter((n): n is string => !!n)
    if (studios.length === 0) continue
    for (const s of studios) {
      buckets.set(s, (buckets.get(s) || 0) + hours)
      total += hours
    }
  }
  if (total === 0) return []
  return [...buckets.entries()]
    .map(([label, hours]) => ({ label, hours, share: hours / total }))
    .sort((a, b) => b.hours - a.hours)
}

export function completion(items: BaseItemDto[]): CompletionStats {
  let completed = 0
  let inProgress = 0
  let unstarted = 0
  for (const it of items) {
    const ud = it.UserData
    const pct = Number(ud?.PlayedPercentage ?? 0)
    if (ud?.Played) completed++
    else if (pct > 0) inProgress++
    else unstarted++
  }
  const total = items.length
  return {
    total,
    completed,
    inProgress,
    unstarted,
    completionRate: total > 0 ? completed / total : 0,
  }
}

/**
 * Top names from item.People filtered by role. Items must have been
 * fetched with `People` in the fields list.
 */
export function topByPersonRole(
  items: BaseItemDto[],
  predicate: (role: string | null | undefined, type: string | null | undefined) => boolean,
  limit = 10,
): PersonShare[] {
  const buckets = new Map<string, number>()
  for (const it of items) {
    const people = (it.People || []) as Array<{ Name?: string | null; Type?: string | null; Role?: string | null }>
    const seen = new Set<string>()
    for (const p of people) {
      if (!p.Name) continue
      if (!predicate(p.Role ?? null, p.Type ?? null)) continue
      if (seen.has(p.Name)) continue
      seen.add(p.Name)
      buckets.set(p.Name, (buckets.get(p.Name) || 0) + 1)
    }
  }
  return [...buckets.entries()]
    .map(([name, count]) => ({ name, count }))
    .sort((a, b) => b.count - a.count)
    .slice(0, limit)
}

/**
 * Sum every per-series time-saved bucket in localStorage. Returns total
 * seconds saved across intros + credits skips.
 */
export function totalTimeSavedSeconds(): { total: number; intros: number; credits: number; series: number } {
  let total = 0
  let intros = 0
  let credits = 0
  let series = 0
  try {
    for (let i = 0; i < localStorage.length; i++) {
      const key = localStorage.key(i)
      if (!key || !key.startsWith(KEY_PREFIX)) continue
      try {
        const parsed = JSON.parse(localStorage.getItem(key) || '{}')
        const ix = Number(parsed.intro) || 0
        const cx = Number(parsed.credits) || 0
        if (ix === 0 && cx === 0) continue
        intros += ix
        credits += cx
        total += ix + cx
        series++
      } catch { /* skip malformed */ }
    }
  } catch { /* localStorage unavailable */ }
  return { total, intros, credits, series }
}
