// Shared types/constants for the /transmission workspace panels. The wire shapes mirror what the
// officer-transmission sidecar returns under /api/transmission/_officer/* — which in turn keeps
// Transmission's own field names, casing warts and all (`percentDone` beside `peer-limit` and
// `sequential_download`). Renaming them here would mean this file and Transmission's rpc-spec.md disagree
// on what a field is called, which is exactly the confusion you don't want at 2am.
//
// The `officer*` fields are the sidecar's own additions — see src/servers/sidecar/transmission/rpc.ts.

export const TRANSMISSION_SECTIONS = [
  { id: 'torrents', label: 'Torrents' },
  { id: 'stats', label: 'Statistics' },
  { id: 'settings', label: 'Settings' },
  { id: 'connection', label: 'Connection' },
] as const;

export type TransmissionSectionId = (typeof TRANSMISSION_SECTIONS)[number]['id'];

/** Where /transmission lands, and where an unrecognised section redirects to. */
export const DEFAULT_TRANSMISSION_SECTION: TransmissionSectionId = 'torrents';

export const isTransmissionSection = (value: string | undefined): value is TransmissionSectionId =>
  TRANSMISSION_SECTIONS.some((s) => s.id === value);

/** The one place the section URL is spelled, so the nav, the guard and any deep link cannot drift apart. */
export const transmissionSectionPath = (id: TransmissionSectionId) => `/transmission/${id}`;

// ── Domain objects ────────────────────────────────────────────────────────────────────────────────

/** Transmission's torrent status enum (rpc-spec.md §3.3). */
export const STATUS = {
  Stopped: 0,
  CheckWait: 1,
  Check: 2,
  DownloadWait: 3,
  Download: 4,
  SeedWait: 5,
  Seed: 6,
} as const;

export type TrackerStat = {
  announce: string;
  announceState: number;
  downloadCount: number;
  hasAnnounced: boolean;
  hasScraped: boolean;
  host: string;
  id: number;
  isBackup: boolean;
  lastAnnouncePeerCount: number;
  lastAnnounceResult: string;
  lastAnnounceSucceeded: boolean;
  lastAnnounceTime: number;
  lastScrapeResult: string;
  lastScrapeSucceeded: boolean;
  lastScrapeTime: number;
  leecherCount: number;
  nextAnnounceTime: number;
  scrape: string;
  seederCount: number;
  tier: number;
};

export type TorrentFile = { bytesCompleted: number; length: number; name: string };
export type TorrentFileStat = { bytesCompleted: number; priority: number; wanted: boolean };

export type TorrentPeer = {
  address: string;
  clientName: string;
  flagStr: string;
  isEncrypted: boolean;
  isIncoming: boolean;
  isUTP: boolean;
  port: number;
  progress: number;
  rateToClient: number;
  rateToPeer: number;
};

export type PeersFrom = {
  fromCache: number;
  fromDht: number;
  fromIncoming: number;
  fromLpd: number;
  fromLtep: number;
  fromPex: number;
  fromTracker: number;
};

export type Torrent = {
  id: number;
  name: string;
  status: number;
  totalSize: number;
  sizeWhenDone: number;
  leftUntilDone: number;
  haveValid: number;
  percentDone: number;
  metadataPercentComplete: number;
  recheckProgress?: number;
  downloadedEver: number;
  uploadedEver: number;
  corruptEver?: number;
  uploadRatio: number;
  rateDownload: number;
  rateUpload: number;
  eta: number;
  peersSendingToUs: number;
  peersGettingFromUs: number;
  addedDate: number;
  doneDate: number;
  activityDate: number;
  secondsSeeding: number;
  downloadDir: string;
  bandwidthPriority: number;
  queuePosition: number;
  isPrivate: boolean;
  labels: string[];
  error: number;
  errorString: string;
  pieceCount: number;
  pieceSize: number;
  magnetLink: string;
  group: string;
  'file-count': number;
  trackerStats: TrackerStat[];
  trackerList?: string;
  honorsSessionLimits: boolean;
  downloadLimited: boolean;
  downloadLimit: number;
  uploadLimited: boolean;
  uploadLimit: number;
  'peer-limit': number;
  seedRatioMode: number;
  seedRatioLimit: number;
  seedIdleMode: number;
  seedIdleLimit: number;
  sequential_download?: boolean;
  // Detail-only — present when fetched through useTorrentDetail.
  hashString?: string;
  comment?: string;
  creator?: string;
  dateCreated?: number;
  maxConnectedPeers?: number;
  files?: TorrentFile[];
  fileStats?: TorrentFileStat[];
  peers?: TorrentPeer[];
  peersFrom?: PeersFrom;
  // Derived by the sidecar.
  officerTrackerHost: string;
  officerTrackerStatus: string;
  officerTrackerErrors: number;
};

export type SessionSettings = Record<string, unknown> & {
  version: string;
  'rpc-version': number;
  'download-dir': string;
};

export type StatsBucket = {
  downloadedBytes: number;
  uploadedBytes: number;
  filesAdded: number;
  sessionCount: number;
  secondsActive: number;
};

export type SessionStats = {
  activeTorrentCount: number;
  pausedTorrentCount: number;
  torrentCount: number;
  downloadSpeed: number;
  uploadSpeed: number;
  'cumulative-stats': StatsBucket;
  'current-stats': StatsBucket;
};

/** The ids the sidecar accepts at POST /_officer/torrents/action. */
export type TorrentAction =
  | 'start'
  | 'start-now'
  | 'stop'
  | 'verify'
  | 'reannounce'
  | 'queue-top'
  | 'queue-up'
  | 'queue-down'
  | 'queue-bottom';

export const PRIORITY = { Low: -1, Normal: 0, High: 1 } as const;

/** Transmission's seedRatioMode / seedIdleMode share this vocabulary. */
export const LIMIT_MODE = { Global: 0, Single: 1, Unlimited: 2 } as const;
