// Lustro modeli z FastAPI app/api/schemas.py + admin endpoints.

export interface ExternalRef {
  source: string;
  external_id: string;
  url?: string | null;
  last_seen?: string | null;
}

export interface StudioOut {
  id: string;
  name: string;
  slug: string;
  network?: string | null;
}

export interface PerformerOut {
  id: string;
  canonical_name: string;
  slug: string;
  gender?: string | null;
  as_alias?: string | null;
}

export interface TagOut {
  id: string;
  name: string;
  slug: string;
}

export interface PlaybackSource {
  id: string;
  origin: string;
  page_url: string;
  embed_url?: string | null;
  stream_url?: string | null;
  quality?: string | null;
  duration_sec?: number | null;
  thumbnail_url?: string | null;
  animated_thumbnail_url?: string | null;
}

export interface StreamLink {
  // proxy URL (fallback gdy direct fails). Backend re-fetchuje content z VPS IP +
  // streamuje do mobile.
  stream_url?: string | null;
  // hoster embed URL — mobile otwiera w WebView gdy `type=hoster`.
  embed_url?: string | null;
  // raw CDN URL + headers do bezpośredniego fetchu z urządzenia (preferred — 0
  // bandwidth przez VPS). Mobile próbuje to PIERWSZE; fallback na `stream_url` na error.
  direct_url?: string | null;
  headers?: Record<string, string> | null;
  quality?: string | null;
  type?: string | null;
  // Backend metadata (origin, host, part_label dla paradisehill multipart, mobile_direct_ok...).
  // Untyped bag — mobile czyta selektywnie (np. raw.part_label w movie part-pickerze).
  raw?: Record<string, unknown> | null;
}

export interface ResolveOut {
  source: PlaybackSource;
  best?: StreamLink | null;
  links: StreamLink[];
}

export interface TagCount {
  id: string;
  name: string;
  slug: string;
  scene_count: number;
}

export interface TagListOut {
  items: TagCount[];
  total: number;
  page: number;
  per_page: number;
}

export interface PerformerCount {
  id: string;
  canonical_name: string;
  slug: string;
  gender?: string | null;
  scene_count: number;
}

export interface PerformerListOut {
  items: PerformerCount[];
  total: number;
  page: number;
  per_page: number;
}

export interface StudioCount {
  id: string;
  name: string;
  slug: string;
  network?: string | null;
  scene_count: number;
}

export interface StudioListOut {
  items: StudioCount[];
  total: number;
  page: number;
  per_page: number;
}

export interface SourceRating {
  stars: number; // 0-5 ogólna (0 = offline)
  freshness: number; // 0-5
  richness: number; // 0-5
  health: number | null; // 0-5 (0=offline), null gdy brak danych
  health_basis?: string | null; // 'telemetry' | 'proxy'
  components?: {
    pct?: Record<string, number>; // thumb/tag/perf/desc/studio/dur (%)
    health_basis?: string;
    mechanism?: string | null;
    pb_attempts_7d?: number;
    pb_success_rate?: number | null;
    p50_ttff_ms?: number | null;
  } | null;
}

export interface SourceOut {
  origin: string;
  sitetag: string;
  display_name: string;
  scene_count: number;
  last_scraped_at: string | null;
  rating?: SourceRating | null;
}

export interface SourceListOut {
  items: SourceOut[];
  total: number;
}

export type ScenesSort = 'created_at' | 'release_date' | 'title' | 'studio';

export interface ScenesListParams {
  q?: string;
  studio_slugs?: string[];
  tags?: string[];
  performer_ids?: string[];
  has_playback?: boolean;
  min_duration_sec?: number;
  max_duration_sec?: number;
  released_within_days?: number;
  min_quality_p?: number;
  include_stubs?: boolean;
  origin?: string;
  sort?: ScenesSort;
  page?: number;
  per_page?: number;
}

export interface SceneOut {
  id: string;
  title: string;
  slug?: string | null;
  release_date?: string | null;
  duration_sec?: number | null;
  description?: string | null;
  code?: string | null;
  director?: string | null;
  studio?: StudioOut | null;
  performers: PerformerOut[];
  tags: TagOut[];
  external_refs: ExternalRef[];
  playback_sources: PlaybackSource[];
  // Kiedy scena trafiła do bazy (ingest). Używane do oznaczenia "NEW" — gdy
  // `created_at > favoriteSeenSince` (param przekazany z FavoritesScreen).
  created_at?: string | null;
  // True = scena z masowego backfillu katalogu (deep-crawl), stara treść, nie świeży
  // release. NIE pokazujemy na niej NEW badge nawet gdy created_at > seenSince.
  backfill?: boolean;
  // Watched indicator + favorite state. Backend dolicza z scene_play_progress + favorite_scenes.
  last_played_at?: string | null;
  finished?: boolean;
  position_sec?: number;
  is_favorite?: boolean;
}

export interface SceneListOut {
  items: SceneOut[];
  total: number;
  page: number;
  per_page: number;
  // has_more: czy jest kolejna strona (z fetcha per_page+1). Paginuj po TYM, nie po
  // `total` — bo dla list filtrowanych `total` jest bounded ("1000+"). Optional dla
  // wstecznej zgodności ze starym backendem (undefined → fallback na total w UI).
  has_more?: boolean;
  // total_capped: true gdy `total` to cap (jest >total wyników) → pokaż "{total}+".
  total_capped?: boolean;
}

export interface MovieChapterOut {
  chapter_index: number;
  title?: string | null;
  start_sec?: number | null;
  end_sec?: number | null;
  scene_id?: string | null;
}

export interface MovieOut {
  id: string;
  title: string;
  slug?: string | null;
  release_year?: number | null;
  release_date?: string | null;
  duration_sec?: number | null;
  description?: string | null;
  director?: string | null;
  country?: string | null;
  rating?: number | null;
  poster_url?: string | null;
  backdrop_url?: string | null;
  studio?: StudioOut | null;
  performers: PerformerOut[];
  tags: TagOut[];
  chapters: MovieChapterOut[];
  external_refs: ExternalRef[];
  playback_sources: PlaybackSource[];
  created_at?: string | null;
  is_favorite?: boolean;
  // Watched / continue-watching state (mirror SceneOut). Backend zaczął
  // zwracać 2026-05-28 — pre-0.2.0 buildy zostawią defaults (false/0/null).
  last_played_at?: string | null;
  finished?: boolean;
  position_sec?: number;
}

export interface MovieListOut {
  items: MovieOut[];
  total: number;
  page: number;
  per_page: number;
}

export interface FavoriteMovieOut {
  movie_id: string;
  title: string;
  slug: string | null;
  poster_url: string | null;
  release_year: number | null;
  studio_name: string | null;
  last_seen_at: string;
  created_at: string;
}

export interface FavoriteMovieListOut {
  items: FavoriteMovieOut[];
  total: number;
}

export interface FavoriteMovieAddOut {
  movie_id: string;
  created: boolean;
}

export type MoviesSort = 'created_at' | 'release_year' | 'release_date' | 'title' | 'rating';

export interface MoviesListParams {
  q?: string;
  studio_slugs?: string[];
  tags?: string[];
  performer_ids?: string[];
  year_from?: number;
  year_to?: number;
  has_playback?: boolean;
  sort?: MoviesSort;
  page?: number;
  per_page?: number;
}

export interface MergeCandidateSummary {
  id: string;
  kind: string;
  left_id: string;
  right_id: string;
  score: number;
  status: 'pending' | 'auto_merged' | 'merged' | 'rejected';
  left_title?: string | null;
  right_title?: string | null;
  left_thumbnail_url?: string | null;
  left_animated_thumbnail_url?: string | null;
  right_thumbnail_url?: string | null;
  right_animated_thumbnail_url?: string | null;
}

export interface MergeCandidateListOut {
  items: MergeCandidateSummary[];
  total: number;
  page: number;
  per_page: number;
}

export interface MergeCandidateDetail {
  id: string;
  kind: string;
  score: number;
  status: string;
  reasons: Record<string, unknown>;
  left: SceneOut | null;
  right: SceneOut | null;
}

export interface ResolveResult {
  id: string;
  status: string;
  keep_id?: string | null;
  drop_id?: string | null;
}

export type ResolveAction = 'merge' | 'reject';
export type KeepSide = 'left' | 'right';

export interface FavoriteOut {
  performer_id: string;
  canonical_name: string;
  slug: string | null;
  scene_count: number;
  new_count: number;
  last_seen_at: string;
  created_at: string;
}

export interface FavoriteListOut {
  items: FavoriteOut[];
  total: number;
  new_total: number;
}

export interface FavoriteAddOut {
  performer_id: string;
  created: boolean;
}

export interface FavoriteStudioOut {
  studio_id: string;
  name: string;
  slug: string;
  network: string | null;
  scene_count: number;
  new_count: number;
  last_seen_at: string;
  created_at: string;
}

export interface FavoriteStudioListOut {
  items: FavoriteStudioOut[];
  total: number;
  new_total: number;
}

export interface FavoriteStudioAddOut {
  studio_id: string;
  created: boolean;
}

export interface BlacklistEntry {
  id: string;
  name: string;
  slug?: string | null;
}

export interface BlacklistOut {
  performers: BlacklistEntry[];
  studios: BlacklistEntry[];
  tags: BlacklistEntry[];
}

export type BlacklistKind = 'performer' | 'studio' | 'tag';

export interface SavedSearchOut {
  id: string;
  query: string;
  created_at: string;
}

export interface ProgressOut {
  scene_id: string;
  position_sec: number;
  duration_sec: number | null;
  finished: boolean;
  last_played_at: string;
}

export interface WatchEntry {
  scene: SceneOut;
  position_sec: number;
  duration_sec: number | null;
  finished: boolean;
  last_played_at: string;
}

export interface WatchListOut {
  items: WatchEntry[];
}
