export type DownloadStatus =
  | "queued"
  | "validating"
  | "downloading"
  | "paused"
  | "reconnect_wait"
  | "extracting"
  | "integrity_check"
  | "completed"
  | "failed"
  | "cancelled";

export type CleanupMode = "none" | "trash" | "delete";
export type ConflictMode = "overwrite" | "skip" | "rename" | "ask";
export type SpeedMode = "global" | "per_download";
export type FinishedCleanupPolicy = "never" | "immediate" | "on_start" | "package_done";
export type DebridProvider =
  | "realdebrid"
  | "megadebrid"
  | "megadebrid-api"
  | "megadebrid-web"
  | "bestdebrid"
  | "alldebrid"
  | "ddownload"
  | "onefichier"
  | "debridlink"
  | "linksnappy";
export type DebridFallbackProvider = DebridProvider | "none";
export type AppTheme = "dark" | "light";
export type PackagePriority = "high" | "normal" | "low";
export type ExtractCpuPriority = "high" | "middle" | "low";
export type HistoryRetentionMode = "never" | "session" | "permanent";

export interface BandwidthScheduleEntry {
  id: string;
  startHour: number;
  endHour: number;
  speedLimitKbps: number;
  enabled: boolean;
}

export interface DownloadStats {
  totalDownloaded: number;
  totalDownloadedAllTime: number;
  totalFiles?: number;
  totalFilesSession: number;
  totalFilesAllTime: number;
  totalPackages: number;
  sessionStartedAt: number;
  appSessionStartedAt: number;
  sessionRuntimeMs: number;
  totalRuntimeMs: number;
  runtimeMeasuredAt: number;
}

export interface DebridAccountStatus {
  accountId: string;
  provider: "megadebrid" | "debridlink";
  label: string;
  maskedLogin: string;
  valid: boolean;
  isPremium: boolean;
  premiumUntilMs: number | null;
  email?: string;
  message: string;
  checkedAt: number;
}

export interface AppSettings {
  token: string;
  realDebridUseWebLogin: boolean;
  megaLogin: string;
  megaPassword: string;
  megaCredentials: string;
  megaDebridApiEnabled: boolean;
  megaDebridWebEnabled: boolean;
  megaDebridPreferApi: boolean;
  bestToken: string;
  bestDebridUseWebLogin: boolean;
  allDebridToken: string;
  allDebridUseWebLogin: boolean;
  ddownloadLogin: string;
  ddownloadPassword: string;
  oneFichierApiKey: string;
  debridLinkApiKeys: string;
  debridLinkDisabledKeyIds: string[];
  linkSnappyLogin: string;
  linkSnappyPassword: string;
  archivePasswordList: string;
  rememberToken: boolean;
  providerOrder: readonly DebridProvider[];
  providerPrimary: DebridProvider;
  providerSecondary: DebridFallbackProvider;
  providerTertiary: DebridFallbackProvider;
  autoProviderFallback: boolean;
  outputDir: string;
  packageName: string;
  autoExtract: boolean;
  autoRename4sf4sj: boolean;
  keepGermanAudioOnly: boolean;
  germanAudioMode: "tag" | "first";
  extractDir: string;
  collectMkvToLibrary: boolean;
  mkvLibraryDir: string;
  createExtractSubfolder: boolean;
  hybridExtract: boolean;
  cleanupMode: CleanupMode;
  extractConflictMode: ConflictMode;
  removeLinkFilesAfterExtract: boolean;
  removeSamplesAfterExtract: boolean;
  enableIntegrityCheck: boolean;
  autoResumeOnStart: boolean;
  autoReconnect: boolean;
  reconnectWaitSeconds: number;
  completedCleanupPolicy: FinishedCleanupPolicy;
  maxParallel: number;
  maxParallelExtract: number;
  retryLimit: number;
  speedLimitEnabled: boolean;
  speedLimitKbps: number;
  speedLimitMode: SpeedMode;
  updateRepo: string;
  autoUpdateCheck: boolean;
  clipboardWatch: boolean;
  minimizeToTray: boolean;
  theme: AppTheme;
  collapseNewPackages: boolean;
  historyRetentionMode: HistoryRetentionMode;
  historyMaxEntries: number;
  historyMaxAgeDays: number;
  accountListShowDetailedDebridLinkKeys: boolean;
  autoSortPackagesByProgress: boolean;
  autoSkipExtracted: boolean;
  hideExtractedItems: boolean;
  confirmDeleteSelection: boolean;
  backupIncludeDownloads: boolean;
  backupIncludeRemoteDiagnostics: boolean;
  notifyUrl: string;
  notifyMention: string;
  notifyOnPackageCompleted: boolean;
  notifyOnPackageFailed: boolean;
  notifyOnRunFinished: boolean;
  totalDownloadedAllTime: number;
  totalCompletedFilesAllTime: number;
  totalRuntimeAllTimeMs: number;
  bandwidthSchedules: BandwidthScheduleEntry[];
  columnOrder: string[];
  extractCpuPriority: ExtractCpuPriority;
  autoExtractWhenStopped: boolean;
  disabledProviders: DebridProvider[];
  hosterRouting: Record<string, DebridProvider>;
  providerDailyLimitBytes: Partial<Record<DebridProvider, number>>;
  providerDailyUsageBytes: Partial<Record<DebridProvider, number>>;
  providerTotalUsageBytes: Partial<Record<DebridProvider, number>>;
  debridLinkApiKeyDailyLimitBytes: Record<string, number>;
  debridLinkApiKeyDailyUsageBytes: Record<string, number>;
  debridLinkApiKeyTotalUsageBytes: Record<string, number>;
  megaDebridDisabledAccountIds: string[];
  megaDebridAccountDailyLimitBytes: Record<string, number>;
  megaDebridAccountDailyUsageBytes: Record<string, number>;
  megaDebridAccountTotalUsageBytes: Record<string, number>;
  debridAccountStatuses: Record<string, DebridAccountStatus>;
  providerDailyUsageDay: string;
  scheduledStartEpochMs: number;
}

export interface DownloadItem {
  id: string;
  packageId: string;
  url: string;
  provider: DebridProvider | null;
  providerLabel?: string;
  providerAccountId?: string;
  providerAccountLabel?: string;
  status: DownloadStatus;
  retries: number;
  speedBps: number;
  downloadedBytes: number;
  totalBytes: number | null;
  progressPercent: number;
  fileName: string;
  targetPath: string;
  resumable: boolean;
  attempts: number;
  lastError: string;
  fullStatus: string;
  createdAt: number;
  updatedAt: number;
  onlineStatus?: "online" | "offline" | "checking";
}

export interface AudioStripFileResult {
  name: string;
  action: string;
  reason: string;
  languages?: string;
}

export interface AudioStripSummary {
  at: number;
  candidates: number;
  remuxed: number;
  keptSingle: number;
  skippedNoGerman: number;
  skippedNoTool: number;
  failed: number;
  files: AudioStripFileResult[];
}

export interface PackageEntry {
  id: string;
  name: string;
  outputDir: string;
  extractDir: string;
  status: DownloadStatus;
  itemIds: string[];
  cancelled: boolean;
  enabled: boolean;
  priority?: PackagePriority;
  postProcessLabel?: string;
  audioStripSummary?: AudioStripSummary;
  downloadStartedAt?: number;
  downloadCompletedAt?: number;
  createdAt: number;
  updatedAt: number;
}

export interface SessionState {
  version: number;
  packageOrder: string[];
  packages: Record<string, PackageEntry>;
  items: Record<string, DownloadItem>;
  runStartedAt: number;
  totalDownloadedBytes: number;
  summaryText: string;
  reconnectUntil: number;
  reconnectReason: string;
  paused: boolean;
  running: boolean;
  updatedAt: number;
}

export interface DownloadSummary {
  total: number;
  success: number;
  failed: number;
  cancelled: number;
  extracted: number;
  durationSeconds: number;
  averageSpeedBps: number;
}

export interface ParsedPackageInput {
  name: string;
  links: string[];
  fileNames?: string[];
}

export interface ContainerImportResult {
  packages: ParsedPackageInput[];
  source: "dlc";
}

export interface RotationEvent {
  id: string;
  at: number;
  level: "INFO" | "WARN" | "ERROR";
  provider: string;
  accountLabel: string;
  event: string;
  reason?: string;
  category?: string;
  cooldownSec?: number;
  next?: string;
}

export interface UiSnapshot {
  settings: AppSettings;
  session: SessionState;
  summary: DownloadSummary | null;
  stats: DownloadStats;
  speedText: string;
  etaText: string;
  canStart: boolean;
  canStop: boolean;
  canPause: boolean;
  clipboardActive: boolean;
  reconnectSeconds: number;
  packageSpeedBps: Record<string, number>;
  payloadKind?: "full" | "delta";
  removedItemIds?: string[];
  removedPackageIds?: string[];
  rotationEvents?: RotationEvent[];
}

export interface AddLinksPayload {
  rawText: string;
  packageName?: string;
  duplicatePolicy?: DuplicatePolicy;
}

export interface AddContainerPayload {
  filePaths: string[];
}

export type DuplicatePolicy = "keep" | "skip" | "overwrite";

export interface QueueAddResult {
  addedPackages: number;
  addedLinks: number;
  skippedExistingPackages: string[];
  overwrittenPackages: string[];
}

export interface ContainerConflictResult {
  conflicts: string[];
  packageCount: number;
  linkCount: number;
}

export interface StartConflictEntry {
  packageId: string;
  packageName: string;
  extractDir: string;
}

export interface StartConflictResolutionResult {
  skipped: boolean;
  overwritten: boolean;
}

export interface UpdateCheckResult {
  updateAvailable: boolean;
  currentVersion: string;
  latestVersion: string;
  latestTag: string;
  releaseUrl: string;
  setupAssetUrl?: string;
  setupAssetName?: string;
  setupAssetDigest?: string;
  releaseNotes?: string;
  error?: string;
}

export interface UpdateInstallResult {
  started: boolean;
  message: string;
}

export interface UpdateInstallProgress {
  stage: "starting" | "downloading" | "verifying" | "launching" | "done" | "error";
  percent: number | null;
  downloadedBytes: number;
  totalBytes: number | null;
  message: string;
}

export type AllDebridHostState = "up" | "down" | "not_tracked" | "unknown";
export type AllDebridHostInfoSource = "api" | "web";
export type DebridLinkHostState = "up" | "down" | "unknown";
export type DebridLinkKeyState = "ready" | "cooldown" | "invalid" | "quota" | "rate_limit" | "error" | "unknown";

export interface AllDebridHostInfo {
  host: string;
  source: AllDebridHostInfoSource;
  state: AllDebridHostState;
  statusLabel: string;
  fetchedAt: number;
  lastCheckedAt: number | null;
  quota: number | null;
  quotaMax: number | null;
  quotaType: string;
  limitSimuDl: number | null;
  note: string;
}

export interface DebridLinkHostLimitInfo {
  keyId: string;
  keyLabel: string;
  host: string;
  fetchedAt: number;
  trafficCurrentBytes: number | null;
  trafficMaxBytes: number | null;
  linksCurrent: number | null;
  linksMax: number | null;
  note: string;
  state: DebridLinkKeyState;
  stateLabel: string;
  stateDetail: string;
  cooldownUntil: number | null;
  cooldownRemainingMs: number;
  lastCheckedAt: number | null;
  hostState: DebridLinkHostState;
  hostStateLabel: string;
  hostNote: string;
}

export interface ParsedHashEntry {
  fileName: string;
  algorithm: "crc32" | "md5" | "sha1";
  digest: string;
}

export interface BandwidthSample {
  timestamp: number;
  speedBps: number;
}

export interface BandwidthStats {
  samples: BandwidthSample[];
  currentSpeedBps: number;
  averageSpeedBps: number;
  maxSpeedBps: number;
  totalBytesSession: number;
  sessionDurationSeconds: number;
}

export interface SessionStats {
  bandwidth: BandwidthStats;
  totalDownloads: number;
  completedDownloads: number;
  failedDownloads: number;
  activeDownloads: number;
  queuedDownloads: number;
}

export interface SupportTraceConfig {
  enabled: boolean;
  includeMainLog: boolean;
  includeAudit: boolean;
  logDebugRequests: boolean;
  autoDisableAt: string | null;
  updatedAt: string;
}

export interface SupportFileSizeInfo {
  path: string | null;
  exists: boolean;
  bytes: number;
}

export interface SupportDirectorySizeInfo {
  path: string;
  exists: boolean;
  fileCount: number;
  bytes: number;
}

export interface SupportDiskSpaceInfo {
  path: string;
  totalBytes: number | null;
  freeBytes: number | null;
  freePercent: number | null;
}

export interface SupportBundleEstimate {
  estimatedBytes: number;
  estimatedEntries: number;
  duplicatedLiveLogBytes: number;
  note: string;
}

export interface DebugSetupCheckResult {
  status: "ok" | "warn";
  enabled: boolean;
  runtimeBaseDir: string;
  host: string;
  port: number;
  localOnly: boolean;
  tokenConfigured: boolean;
  tokenPath: string;
  supportManifestPath: string;
  supportManifestPresent: boolean;
  traceConfigPath: string | null;
  traceLogPath: string | null;
  traceEnabled: boolean;
  traceAutoDisableAt: string | null;
  diskSpace: {
    runtime: SupportDiskSpaceInfo;
    output: SupportDiskSpaceInfo;
    extract: SupportDiskSpaceInfo;
  };
  logSummary: {
    totalBytes: number;
    main: SupportFileSizeInfo;
    mainBackup: SupportFileSizeInfo;
    audit: SupportFileSizeInfo;
    auditBackup: SupportFileSizeInfo;
    rename: SupportFileSizeInfo;
    renameBackup: SupportFileSizeInfo;
    session: SupportFileSizeInfo;
    trace: SupportFileSizeInfo;
    traceBackup: SupportFileSizeInfo;
    sessionLogs: SupportDirectorySizeInfo;
    packageLogs: SupportDirectorySizeInfo;
    itemLogs: SupportDirectorySizeInfo;
  };
  supportBundle: SupportBundleEstimate;
  warnings: string[];
  notes: string[];
  localUrls: {
    health: string;
    meta: string;
    diagnostics: string;
  };
  remoteUrlTemplates: {
    health: string;
    meta: string;
    diagnostics: string;
  };
}

export interface HistoryEntry {
  id: string;
  name: string;
  totalBytes: number;
  downloadedBytes: number;
  fileCount: number;
  provider: DebridProvider | null;
  completedAt: number;
  durationSeconds: number;
  status: "completed" | "deleted";
  outputDir: string;
  urls?: string[];
}

export interface HistoryState {
  entries: HistoryEntry[];
  maxEntries: number;
}

export interface RendererErrorReport {
  kind: "error" | "unhandledrejection" | "react";
  message: string;
  stack?: string;
  source?: string;
  line?: number;
  column?: number;
  componentStack?: string;
}

export interface RemoteDiagnosticsStatus {
  running: boolean;
  host: string;
  port: number;
  hasToken: boolean;
  localOnly: boolean;
  allowlistCount: number;
}

export interface RemoteDiagnosticsInfo {
  status: RemoteDiagnosticsStatus;
  code: string | null;
  publicHost: string;
  name: string;
  allowlist: string[];
  suggestedHosts: string[];
}

export interface EnableRemoteDiagnosticsInput {
  hostMode: "local" | "network";
  publicHost: string;
  port?: number;
  allowlist: string[];
  name?: string;
  rotateToken?: boolean;
}
