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

/**
 * Override rules let the user automate request routing. Example: if
 * the genre includes "Anime", route to the Anime tier of Sonarr with a
 * specific quality profile and root folder.
 *
 * Rules are evaluated at request time in declaration order; the first
 * one whose conditions match wins. Anything unset in the matched rule
 * falls back to the picked instance's defaults, so a rule can override
 * a single field without specifying everything.
 */

export interface OverrideRule {
  id: string
  name: string
  /** Restrict to which kind of media this rule applies to. */
  kind: 'movie' | 'tv' | 'any'
  /** Condition: any of these genre names triggers (case-insensitive).
   *  Empty array means "any genre". */
  genres: string[]
  /** Condition: original-language ISO codes (e.g. "ja", "ko"). Empty = any. */
  languages: string[]
  /** Condition: year range (inclusive). null bound = open-ended. */
  yearMin?: number
  yearMax?: number
  /** Condition: TMDB keyword ids. Empty = any. */
  keywordIds: number[]

  /** Action: pick this tier (regular vs 4K). */
  tier?: 'default' | '4k'
  /** Action: override quality profile id within the picked instance. */
  qualityProfileId?: number
  /** Action: override root folder path. */
  rootFolderPath?: string
  /** Action: override Sonarr language profile id. */
  languageProfileId?: number
  /** Action: append tag ids to the request. */
  tagIds?: number[]

  enabled: boolean
  createdAt: string
}

interface State {
  rules: OverrideRule[]
  add: (rule: Omit<OverrideRule, 'id' | 'createdAt'>) => OverrideRule
  update: (id: string, patch: Partial<OverrideRule>) => void
  remove: (id: string) => void
  reorder: (id: string, direction: -1 | 1) => void
}

function uid() {
  return 'rule_' + Math.random().toString(36).slice(2, 10) + Date.now().toString(36)
}

export const useOverrideRules = create<State>()(
  persist(
    set => ({
      rules: [],
      add: input => {
        const next: OverrideRule = {
          ...input,
          id: uid(),
          createdAt: new Date().toISOString(),
        }
        set(s => ({ rules: [...s.rules, next] }))
        return next
      },
      update: (id, patch) =>
        set(s => ({
          rules: s.rules.map(r => (r.id === id ? { ...r, ...patch } : r)),
        })),
      remove: id => set(s => ({ rules: s.rules.filter(r => r.id !== id) })),
      reorder: (id, direction) =>
        set(s => {
          const idx = s.rules.findIndex(r => r.id === id)
          const target = idx + direction
          if (idx < 0 || target < 0 || target >= s.rules.length) return s
          const next = [...s.rules]
          const [item] = next.splice(idx, 1)
          next.splice(target, 0, item)
          return { rules: next }
        }),
    }),
    { name: 'override-rules-v1' },
  ),
)

export interface OverrideContext {
  kind: 'movie' | 'tv'
  genres: string[]
  originalLanguage: string | null
  year: number | null
  keywordIds: number[]
}

/**
 * Evaluate active rules against an item and return the resulting
 * override patch (or null when nothing matches). The first matching
 * enabled rule wins.
 */
export function applyOverrideRules(
  rules: OverrideRule[],
  ctx: OverrideContext,
): Partial<OverrideRule> | null {
  for (const rule of rules) {
    if (!rule.enabled) continue
    if (rule.kind !== 'any' && rule.kind !== ctx.kind) continue
    if (rule.genres.length > 0) {
      const want = new Set(rule.genres.map(g => g.toLowerCase()))
      const have = new Set((ctx.genres || []).map(g => g.toLowerCase()))
      const overlaps = [...want].some(g => have.has(g))
      if (!overlaps) continue
    }
    if (rule.languages.length > 0) {
      const want = new Set(rule.languages.map(l => l.toLowerCase()))
      if (!ctx.originalLanguage || !want.has(ctx.originalLanguage.toLowerCase())) continue
    }
    if (rule.yearMin != null && (ctx.year == null || ctx.year < rule.yearMin)) continue
    if (rule.yearMax != null && (ctx.year == null || ctx.year > rule.yearMax)) continue
    if (rule.keywordIds.length > 0) {
      const have = new Set(ctx.keywordIds || [])
      if (!rule.keywordIds.some(k => have.has(k))) continue
    }
    return {
      tier: rule.tier,
      qualityProfileId: rule.qualityProfileId,
      rootFolderPath: rule.rootFolderPath,
      languageProfileId: rule.languageProfileId,
      tagIds: rule.tagIds,
    }
  }
  return null
}
