/**
 * Thin Sonarr v3 API client. Same shape as the Radarr client - same
 * auth, same null-on-failure convention - but the data model is
 * series + seasons + episodes rather than movies, and Sonarr keys off
 * TVDB ids natively (TMDB ids are accepted via `lookup?term=tmdb:N`).
 */

import type { ArrInstance } from '../stores/arr-instances-store'

export interface SonarrRootFolder {
  id: number
  path: string
  freeSpace?: number
}

export interface SonarrQualityProfile {
  id: number
  name: string
}

export interface SonarrLanguageProfile {
  id: number
  name: string
}

export interface SonarrTag {
  id: number
  label: string
}

export interface SonarrSeason {
  seasonNumber: number
  monitored: boolean
  statistics?: {
    episodeCount: number
    episodeFileCount: number
    totalEpisodeCount: number
    sizeOnDisk: number
    percentOfEpisodes: number
  }
}

export interface SonarrSeries {
  id?: number
  title: string
  titleSlug?: string
  year?: number
  tvdbId?: number
  tmdbId?: number
  imdbId?: string | null
  status?: 'continuing' | 'ended' | 'upcoming' | 'deleted'
  monitored?: boolean
  seasons?: SonarrSeason[]
  qualityProfileId?: number
  languageProfileId?: number
  rootFolderPath?: string
  tags?: number[]
  added?: string
  images?: { coverType: string; remoteUrl?: string; url?: string }[]
}

export interface SonarrLookupResult extends SonarrSeries {
  folder?: string
}

export interface SonarrQueueItem {
  id: number
  seriesId?: number
  episodeId?: number
  seasonNumber?: number
  title: string
  status: string
  trackedDownloadStatus?: string
  size?: number
  sizeleft?: number
  timeleft?: string
}

export interface SonarrSystemStatus {
  version: string
  startTime?: string
  branch?: string
  isProduction?: boolean
}

export interface AddSonarrSeriesPayload {
  tvdbId: number
  qualityProfileId: number
  languageProfileId?: number
  rootFolderPath: string
  monitored?: boolean
  seasonFolder?: boolean
  searchOnAdd?: boolean
  tags?: number[]
  title: string
  titleSlug: string
  year: number
  images?: { coverType: string; remoteUrl?: string; url?: string }[]
  /** Per-season monitor flags so the user can pick which seasons to fetch. */
  seasons: { seasonNumber: number; monitored: boolean }[]
}

export function buildAddSonarrSeriesBody(payload: AddSonarrSeriesPayload) {
  const body: {
    tvdbId: number
    qualityProfileId: number
    rootFolderPath: string
    monitored: boolean
    seasonFolder: boolean
    title: string
    titleSlug: string
    year: number
    images: { coverType: string; remoteUrl?: string; url?: string }[]
    tags: number[]
    seasons?: SonarrSeason[]
    languageProfileId?: number
    addOptions: {
      searchForMissingEpisodes: boolean
      searchForCutoffUnmetEpisodes: boolean
      monitor: 'all'
    }
  } = {
    tvdbId: payload.tvdbId,
    qualityProfileId: payload.qualityProfileId,
    rootFolderPath: payload.rootFolderPath,
    monitored: payload.monitored ?? true,
    seasonFolder: payload.seasonFolder ?? true,
    title: payload.title,
    titleSlug: payload.titleSlug,
    year: payload.year,
    images: payload.images || [],
    tags: payload.tags || [],
    seasons: payload.seasons,
    addOptions: {
      searchForMissingEpisodes: payload.searchOnAdd ?? true,
      searchForCutoffUnmetEpisodes: false,
      monitor: 'all',
    },
  }
  if (payload.languageProfileId != null) body.languageProfileId = payload.languageProfileId
  return body
}

class SonarrClient {
  instance: ArrInstance
  constructor(instance: ArrInstance) {
    this.instance = instance
  }

  private url(path: string): string {
    const base = this.instance.baseUrl.replace(/\/+$/, '')
    return `${base}/api/v3${path}`
  }

  private async req<T>(path: string, init: RequestInit = {}): Promise<T | null> {
    try {
      const res = await fetch(this.url(path), {
        ...init,
        headers: {
          'X-Api-Key': this.instance.apiKey,
          'Content-Type': 'application/json',
          ...(init.headers || {}),
        },
      })
      if (!res.ok) return null
      const text = await res.text()
      return text ? (JSON.parse(text) as T) : (null as unknown as T)
    } catch {
      return null
    }
  }

  systemStatus() { return this.req<SonarrSystemStatus>('/system/status') }
  qualityProfiles() { return this.req<SonarrQualityProfile[]>('/qualityprofile') }
  languageProfiles() { return this.req<SonarrLanguageProfile[]>('/languageprofile') }
  rootFolders() { return this.req<SonarrRootFolder[]>('/rootfolder') }
  tags() { return this.req<SonarrTag[]>('/tag') }
  series() { return this.req<SonarrSeries[]>('/series') }
  queue() { return this.req<{ records: SonarrQueueItem[] }>('/queue') }

  /**
   * Series lookup by TVDB id (preferred), IMDB id (`imdb:tt...`), or
   * TMDB id (`tmdb:N`). Sonarr accepts the term-prefix syntax for the
   * latter two.
   */
  lookup(term: string) {
    return this.req<SonarrLookupResult[]>(
      `/series/lookup?term=${encodeURIComponent(term)}`,
    )
  }
  lookupByTvdbId(tvdbId: number) { return this.lookup(`tvdb:${tvdbId}`) }
  lookupByImdbId(imdbId: string) { return this.lookup(`imdb:${imdbId}`) }
  lookupByTmdbId(tmdbId: number) { return this.lookup(`tmdb:${tmdbId}`) }

  async addSeries(payload: AddSonarrSeriesPayload): Promise<SonarrSeries | null> {
    const body = buildAddSonarrSeriesBody(payload)
    return this.req<SonarrSeries>('/series', {
      method: 'POST',
      body: JSON.stringify(body),
    })
  }

  /**
   * Update an existing series - used when the user changes which seasons
   * to monitor or swaps quality profile.
   */
  updateSeries(series: SonarrSeries) {
    if (!series.id) return Promise.resolve(null)
    return this.req<SonarrSeries>(`/series/${series.id}`, {
      method: 'PUT',
      body: JSON.stringify(series),
    })
  }

  removeSeries(id: number, deleteFiles = false) {
    return this.req<void>(
      `/series/${id}?deleteFiles=${deleteFiles ? 'true' : 'false'}&addImportListExclusion=false`,
      { method: 'DELETE' },
    )
  }

  searchSeries(id: number) {
    return this.req<void>('/command', {
      method: 'POST',
      body: JSON.stringify({ name: 'SeriesSearch', seriesId: id }),
    })
  }

  searchSeason(seriesId: number, seasonNumber: number) {
    return this.req<void>('/command', {
      method: 'POST',
      body: JSON.stringify({ name: 'SeasonSearch', seriesId, seasonNumber }),
    })
  }
}

export function sonarrClient(instance: ArrInstance) {
  return new SonarrClient(instance)
}
