import {
  pgTable,
  pgEnum,
  uuid,
  text,
  integer,
  boolean,
  timestamp,
  jsonb,
  numeric,
} from "drizzle-orm/pg-core";
import { storageTierEnum } from "./storage";
import { mediaItems } from "./media";
import { users } from "./users";

export const qualityEnum = pgEnum("quality", ["sd", "720p", "1080p", "4k"]);

export const overrideTypeEnum = pgEnum("override_type", [
  "force_live",
  "force_archive",
  "force_quality",
  "force_monitor",
  "force_ignore",
  "temporary_promotion",
  // Purged: deliberately removed and not to come back on its own.
  //
  // Distinct from force_ignore, which outranks everything including someone
  // actively watching. `purge` loses to Watching Now and beats every other
  // demand source -- so a purged show can still be pulled back by watching it,
  // and returns to purged once that stops, instead of being quietly re-archived
  // because it is sitting on somebody's Plex watchlist.
  "purge",
]);

export const policyTriggerEnum = pgEnum("policy_trigger", [
  "scheduled",
  "manual",
  "demand_change",
  "metadata_refresh",
]);

// How big a release is allowed to be, in MB per minute of runtime.
//
// Per MINUTE because runtime is the great leveller: a three-hour film and a
// half-hour episode are not the same file and never were, and the rule that
// preceded this -- one nominal size times four -- is how a 12GB "1080p" film
// got grabbed.
//
// These live in the database rather than in the indexer's source because they
// are a policy, not a constant: they were derived from percentiles over this
// library's own probed files, and the right numbers change as the library does.
// The indexer keeps the same values compiled in as a fallback for when this
// table cannot be read, so a database outage cannot silently remove the ceiling.
//
// atmosMaxMbPerMinute is the allowance for object-based audio, and only 4K
// carries one. It is measured: on 4K files, probed TrueHD runs about 1.8x
// E-AC-3 and 4x AAC per minute. Null means no allowance -- the ordinary maximum
// applies whatever the release calls itself.
export const releaseSizeRules = pgTable("release_size_rules", {
  quality: qualityEnum("quality").primaryKey(),
  minMbPerMinute: numeric("min_mb_per_minute", { precision: 6, scale: 1 }).notNull(),
  maxMbPerMinute: numeric("max_mb_per_minute", { precision: 6, scale: 1 }).notNull(),
  atmosMaxMbPerMinute: numeric("atmos_max_mb_per_minute", { precision: 6, scale: 1 }),
  // The remux allowance, and the only ceiling that admits a lossless copy.
  //
  // Applies to nothing except titles marked timeless (the `classics` table). A
  // remux is the disc's own streams repackaged without re-encoding, so it is
  // three to four times the size of a good WEB-DL for a difference most
  // watching does not resolve -- worth the disk for a film chosen to keep
  // forever, and not worth it for anything else. That the allowance is opt-in
  // per title is the whole point: as a global ceiling it would simply become
  // the size everything arrives at.
  timelessMaxMbPerMinute: numeric("timeless_max_mb_per_minute", { precision: 6, scale: 1 }),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

// Admin-level overrides that win over computed policy.
export const adminOverrides = pgTable("admin_overrides", {
  id: uuid("id").primaryKey().defaultRandom(),
  mediaItemId: uuid("media_item_id").notNull().references(() => mediaItems.id, { onDelete: "cascade" }),
  seasonNumber: integer("season_number"),
  episodeNumber: integer("episode_number"),
  overrideType: overrideTypeEnum("override_type").notNull(),
  value: jsonb("value"),
  reason: text("reason"),
  expiresAt: timestamp("expires_at"),
  createdBy: uuid("created_by").references(() => users.id),
  createdAt: timestamp("created_at").notNull().defaultNow(),
});

// Audit record of each policy computation run.
export const policyRuns = pgTable("policy_runs", {
  id: uuid("id").primaryKey().defaultRandom(),
  trigger: policyTriggerEnum("trigger").notNull(),
  startedAt: timestamp("started_at").notNull().defaultNow(),
  completedAt: timestamp("completed_at"),
  itemsEvaluated: integer("items_evaluated"),
  itemsChanged: integer("items_changed"),
});

// Computed desired state for each media item (and optionally each season/episode).
// Recomputed on each policy run. reason_codes explain why this state was chosen.
export const desiredStates = pgTable("desired_states", {
  id: uuid("id").primaryKey().defaultRandom(),
  policyRunId: uuid("policy_run_id").references(() => policyRuns.id),
  mediaItemId: uuid("media_item_id").notNull().references(() => mediaItems.id, { onDelete: "cascade" }),
  seasonNumber: integer("season_number"),
  episodeNumber: integer("episode_number"),
  wanted: boolean("wanted").notNull().default(false),
  storageTier: storageTierEnum("storage_tier"),
  minQuality: qualityEnum("min_quality"),
  preferredQuality: qualityEnum("preferred_quality"),
  monitored: boolean("monitored").notNull().default(false),
  // Array of reason codes, e.g. ["watching_now", "currently_airing"]
  reasonCodes: text("reason_codes").array().notNull().default([]),
  computedAt: timestamp("computed_at").notNull().defaultNow(),
});
