/**
 * API response type definitions for Nexus backend
 *
 * Centralizes all response shapes to eliminate `as any` casts.
 */

/** Generic paginated list response — most list endpoints return this */
export interface PaginatedResponse<T> {
  items: T[]
  total: number
  page?: number
  per_page?: number
  pages?: number
  limit?: number
  offset?: number
}

/** Settings list response — backend returns flat array */
export type SettingsResponse = SettingItem[]

export interface SettingItem {
  key: string
  value: unknown
  value_set?: boolean | null
  updated_at?: string
}

/** Telegram getUpdates chat detection */
export interface TelegramChatItem {
  id: number
  type: string
  title: string
  username: string
}

export interface TelegramChatsResponse {
  chats: TelegramChatItem[]
  count: number
}

export interface OpsPatrolEnvStatus {
  app_env_token: boolean
  app_env_chat_id: boolean
  host_env_prod_token: boolean
  host_env_prod_chat_id: boolean
  env_synced: boolean
}

export interface OpsPatrolStatusResponse {
  telegram_app_configured: boolean
  telegram_layer3_ready: boolean
  telegram_env_synced: boolean
  env_status: OpsPatrolEnvStatus
  db_fallback_enabled: boolean
  cron_install_command: string
  health_log_path: string
}

export interface OpsPatrolSyncResponse {
  synced: Record<string, boolean | string>
  env_status: OpsPatrolEnvStatus
  telegram_layer3_ready: boolean
}

/** Telegram notification toggle (settings key → label) */
export interface NotifyToggleItem {
  key: string
  label: string
  desc: string
  group: string
}

export const NOTIFY_TOGGLE_ITEMS: NotifyToggleItem[] = [
  { key: 'notify_alert_cpu', label: 'CPU 超阈值告警', desc: 'CPU 超阈值或恢复时推送；关闭则该类告警与恢复均不通知', group: '服务器资源' },
  { key: 'notify_alert_mem', label: '内存超阈值告警', desc: '内存超阈值或恢复时推送；关闭则该类告警与恢复均不通知', group: '服务器资源' },
  { key: 'notify_alert_disk', label: '磁盘超阈值告警', desc: '磁盘超阈值或恢复时推送；关闭则该类告警与恢复均不通知', group: '服务器资源' },
  { key: 'notify_recovery', label: '资源恢复正常', desc: 'CPU/内存/磁盘回落正常时推送（须总开关开启且对应资源开关未关）', group: '服务器资源' },
  { key: 'notify_alert_offline', label: '子机离线告警', desc: 'Agent 心跳丢失、子机由在线变为离线时推送一次；可在下方配置专用 Telegram Bot', group: '服务器' },
  { key: 'notify_time_drift', label: '时钟偏差严重 (≥60s)', desc: '子机与主机时间偏差过大影响 TOTP/cron', group: '服务器' },
  { key: 'notify_system_redis', label: 'Redis 连接异常 / 恢复', desc: 'Redis 不可达或恢复时推送', group: '系统' },
  { key: 'notify_system_mysql', label: 'MySQL 连接异常 / 恢复', desc: 'MySQL 不可达或恢复时推送', group: '系统' },
  { key: 'notify_restart', label: 'Nexus 后端重启', desc: 'Python 服务崩溃重启成功/失败时推送', group: '系统' },
  { key: 'notify_script_complete', label: '脚本执行完成', desc: '脚本批量执行结束时推送汇总与看板链接（不含失败明细）', group: '运维' },
]

/** IP Allowlist response */
export interface AllowlistResponse {
  enabled: boolean
  subscription_url?: string
  subscription_ips?: string[]
  manual_ips?: string[]
  subscription_count?: number
  manual_count?: number
  total_count?: number
  last_refresh?: string | null
}

export interface SubscriptionParseResponse {
  hosts: string[]
  count: number
}

export interface IpAllowlistSaveRequest {
  manual_ips?: string[]
  subscription_url?: string | null
  enabled?: boolean
}

export interface IpAllowlistSaveResponse {
  success: boolean
  manual_count: number
  subscription_ips?: string[]
  subscription_count?: number
  last_refresh?: string | null
  refresh_ok?: boolean
  refresh_error?: string | null
}

/** File browse response from POST /api/sync/browse */
export interface BrowseResponse {
  path?: string
  items: FileEntry[]
  /** SSH/listing failure message when items is empty */
  error?: string
}

export interface FileEntry {
  name: string
  type: 'directory' | 'file' | 'symlink'
  size: number
  modified: string
  permissions: string
  owner?: string
  group?: string
  mode_octal?: string
  link_target?: string | null
}

export type FilesElevationMode = 'off' | 'auto_sudo' | 'always_sudo'

export interface FilesCapabilityResult {
  ssh_user: string
  is_root: boolean
  files_elevation: FilesElevationMode
  can_sudo_nopasswd: boolean
  whitelist_ok: boolean
  message: string
  docs_path: string
}

/** Server item from /api/servers/ */
export type ServerAgentAction = 'install' | 'upgrade' | 'offline' | 'ok'

export interface ServerApiItem {
  id: number
  name: string
  domain: string
  port: number
  username: string
  auth_method: string
  password_set: boolean
  ssh_key_path: string
  ssh_key_public: string
  ssh_key_private_set: boolean
  agent_port: number
  agent_api_key: string
  agent_api_key_set: boolean
  preset_id: number | null
  ssh_key_preset_id: number | null
  description: string
  target_path: string
  category: string | null
  platform_id: number | null
  node_id: number | null
  files_elevation?: FilesElevationMode
  is_online: boolean
  last_heartbeat: string | null
  agent_version: string | null
  status: string
  agent_action?: ServerAgentAction
  agent_action_message?: string | null
  central_agent_version?: string | null
  created_at: string | null
  updated_at: string | null
  system_info?: {
    cpu_usage?: number
    mem_usage?: number
    disk_usage?: number
    [key: string]: unknown
  }
  connectivity?: string
  ssh_key_configured?: boolean
  last_checked_at?: string | null
  protocols?: Record<string, unknown>
  extra_attrs?: Record<string, unknown>
  _source?: string
}

/** GET /api/servers/{id}/metrics — per-server 10min samples */
export interface ServerMetricPoint {
  recorded_at: string
  is_online: boolean
  cpu_pct: number | null
  mem_pct: number | null
}

export interface ServerMetricOfflineSegment {
  from: string
  to: string
}

export interface ServerMetricsResponse {
  server_id: number
  hours: number
  interval_minutes: number
  points: ServerMetricPoint[]
  offline_segments: ServerMetricOfflineSegment[]
}

/** Credential poll error from add-by-ip / pending retry */
export interface PollErrorItem {
  preset_type: string
  preset_name: string
  username: string
  error: string
}

/** Pending server row from GET /api/servers/pending */
export interface PendingServerItem {
  id: number
  name: string
  domain: string
  port: number
  attempts: number
  last_error: string
  last_attempt_at: string | null
  agent_port?: number
  target_path?: string
  category?: string | null
  platform_id?: number | null
  node_id?: number | null
  created_at?: string | null
}

/** Response from POST /api/servers/batch/category (legacy sync — deprecated) */
export interface BatchCategoryResult {
  updated: number
  not_found: number[]
}

/** Response from POST /api/servers/batch/* and /api/servers/check (background job) */
export interface BatchJobStarted {
  job_id: number
  status: string
  label: string
  op: string
  total: number
  done: number
  remaining: number
  success: number
  failed: number
  progress: string
}

/** Response from POST /api/servers/add-by-ip and pending retry */
export interface AddByIpResponse {
  success: boolean
  server?: ServerApiItem
  pending_id?: number
  errors?: PollErrorItem[]
  message?: string
  matched_preset?: string
  matched_username?: string
  onboarding_job_id?: number
  onboarding_label?: string
}

/** Item from POST /api/servers/add-by-ips-batch */
export interface AddByIpsBatchItemResult {
  domain: string
  status: 'created' | 'pending' | 'skipped'
  server_id?: number
  pending_id?: number
  message?: string
  matched_preset?: string
  matched_username?: string
  errors?: PollErrorItem[]
}

/** Response from POST /api/servers/add-by-ips-batch */
export interface AddByIpsBatchResult {
  total: number
  created: number
  pending: number
  skipped: number
  input_lines?: number
  duplicates_removed?: number
  items: AddByIpsBatchItemResult[]
  onboarding_job_id?: number
}

/** Alert history item from /api/alert-history/ */
export interface AlertLogItem {
  id: number
  server_id: number
  server_name: string
  alert_type: string
  value: string
  is_recovery: boolean
  created_at: string | null
}

/** Command log item from /api/assets/command-logs */
export interface CommandLogItem {
  id: number
  session_id: string | null
  server_id: number
  server_name: string | null
  admin_id: number
  admin_username: string | null
  command: string
  remote_addr: string | null
  created_at: string | null
}

/** SSH session item from /api/assets/ssh-sessions */
export interface SshSessionItem {
  id: number
  server_id: number
  server_name: string | null
  admin_id: number
  remote_addr: string | null
  status: string
  started_at: string | null
  closed_at: string | null
}

/** Retry item from /api/retries/ */
export interface RetryItem {
  id: number
  server_id: number
  server_name: string
  operation: string
  status: string
  last_error: string | null
  operator?: string
  source_path?: string
  target_path?: string
  max_retries?: number
  next_retry_at?: string | null
  retry_count: number
  created_at: string | null
}

/** Script item from /api/scripts/ */
export interface ScriptItem {
  id: number
  name: string
  category: string | null
  description: string | null
  content: string | null
  created_by?: string | null
  created_at: string | null
  updated_at: string | null
}

/** Push history item from GET /api/servers/logs */
export interface PushItem {
  id: number
  server_id: number
  server_name: string | null
  source_path: string
  target_path: string
  status: string
  sync_mode?: string
  trigger_type?: string
  operator?: string | null
  duration_seconds?: number
  error_message?: string | null
  /** rsync --chown/--chmod snapshot, e.g. "chown=www:www chmod=D755,F755" */
  push_permission?: string | null
  started_at: string | null
  finished_at?: string | null
}

/** Schedule item from /api/schedules/ */
export interface ScheduleItem {
  id: number
  name: string
  cron_expr: string | null
  fire_at?: string | null
  command?: string
  source_path?: string
  target_path?: string
  server_ids?: number[]
  run_mode?: string
  sync_mode?: string
  schedule_type?: string
  script_id?: number | null
  script_content?: string
  exec_timeout?: number
  long_task?: boolean
  enabled: boolean
  last_run_at: string | null
  next_run: string | null
  created_at: string | null
}

/** Audit log item from /api/audit/ */
export interface AuditItem {
  id: number
  admin_username: string
  action: string
  /** API 字段为 target_type；兼容旧字段名 */
  resource_type: string
  target_type?: string
  resource_id: number | null
  target_id?: number | null
  detail: string | null
  ip_address: string | null
  created_at: string | null
  /** 目标为 server 时由 API 解析的服务器名称 */
  target_name?: string | null
}

/** DB credential from /api/scripts/credentials (password never returned) */
export interface DbCredentialItem {
  id: number
  name: string
  db_type?: string
  host: string
  port: number
  username: string
  database?: string
  created_at?: string | null
}

/** Script execution item from /api/scripts/executions */
export interface ScriptExecItem {
  id: number
  script_id: number | null
  command: string
  server_ids: string
  status: string
  results: Record<string, {
    status?: string
    phase?: string
    stdout?: string
    stderr?: string
    message?: string
    exit_code?: number
  }>
  events: Array<{ at?: string; action?: string; detail?: string; operator?: string }>
  operator: string | null
  started_at: string | null
  completed_at: string | null
  long_task?: boolean
  progress?: string
  label?: string
  credential_id?: number | null
  source?: string
  /** id → name，由 /executions/{id} 按本批次 server_ids 批量解析 */
  server_names?: Record<string, string>
  /** Unified execution records: script | server_batch */
  kind?: 'script' | 'server_batch'
  op?: string
}

export interface ExecutionRecordItem {
  id: number
  kind: 'script' | 'server_batch'
  label: string
  status: string
  progress: string
  server_count: number
  operator: string
  started_at: string | null
  completed_at: string | null
  command?: string | null
  op?: string | null
}

/** Alert history stats from /api/alert-history/stats */
export interface AlertStatsResponse {
  today: number
  active: number
  recovered: number
  top_server: string
  top_types?: { alert_type: string; count: number }[]
  top_servers?: { server_id: number; server_name: string; count: number }[]
  daily?: { day: string; alerts: number; recoveries: number }[]
}
