/** Terminal API client — supports local + server terminal modes. */

import { BaseApiClient, getDynamicBaseURL } from './base'

const API_BASE = '/api/v1'

export interface ICommandRecord {
  command: string
  exit_code: number
  output: string
  cwd: string
  timestamp: number
  duration_ms: number
}

export interface ITerminalSession {
  session_id: string
  cwd: string
  created_at: number
}

export interface IExecuteResponse {
  session_id: string
  command: string
  exit_code: number
  output: string
  cwd: string
  duration_ms: number
  confirmation_required?: boolean
  reason?: string
}

// ── Whitelist / Blocklist / Audit / Approval types ───────────────────

export interface IWhitelistEntry {
  id: string
  user_id?: string
  command_pattern: string
  scope: 'user' | 'global'
  created_at: string
}

export interface IBlocklistEntry {
  id: string
  command_pattern: string
  reason: string
  created_at: string
}

export interface IAuditLogEntry {
  id: string
  user_id: string | null
  session_id: string
  command: string
  decision: string
  reason: string | null
  exit_code: number | null
  terminal_mode: string
  created_at: string
}

export interface IApprovalEntry {
  id: string
  user_id: string
  username: string
  session_id: string
  command: string
  reason: string | null
  status: 'pending' | 'approved' | 'rejected' | 'expired' | 'cancelled'
  reviewer_id: string | null
  reviewer_username: string | null
  review_note: string | null
  created_at: string
  reviewed_at: string | null
  expires_at: string
}

class TerminalApiClient extends BaseApiClient {
  constructor(baseUrl: string = API_BASE) {
    super(baseUrl)
  }

  /** Create a local terminal WebSocket URL (Tauri-aware, JWT-authenticated). */
  createTerminalWsUrl(sessionId?: string): string {
    const token = this.getToken()
    const params = new URLSearchParams()
    if (sessionId) params.set('session_id', sessionId)
    if (token) params.set('token', token)
    const query = params.toString() ? `?${params.toString()}` : ''

    const dynamicBase = getDynamicBaseURL()
    if (dynamicBase) {
      const url = new URL(dynamicBase)
      const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'
      return `${protocol}//${url.host}${this.baseUrl}/terminal/ws${query}`
    }
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const host = window.location.host
    return `${protocol}//${host}${this.baseUrl}/terminal/ws${query}`
  }

  /**
   * Create a server terminal WebSocket URL with JWT authentication.
   *
   * Server terminal requires ``TERMINAL_SERVER_USE`` permission and the
   * ``is_server_terminal_authorized`` DB flag. The JWT is passed as a
   * ``?token=`` query parameter since browsers cannot set Authorization
   * headers on WebSocket connections.
   */
  createServerTerminalWsUrl(sessionId?: string): string {
    const token = this.getToken()
    const params = new URLSearchParams()
    if (sessionId) params.set('session_id', sessionId)
    if (token) params.set('token', token)
    const query = params.toString() ? `?${params.toString()}` : ''

    const dynamicBase = getDynamicBaseURL()
    if (dynamicBase) {
      const url = new URL(dynamicBase)
      const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'
      return `${protocol}//${url.host}${this.baseUrl}/terminal/server/ws${query}`
    }
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const host = window.location.host
    return `${protocol}//${host}${this.baseUrl}/terminal/server/ws${query}`
  }

  /** Execute a command via REST API */
  async executeCommand(
    command: string,
    sessionId?: string
  ): Promise<IExecuteResponse> {
    return this.request<IExecuteResponse>('/terminal/execute', {
      method: 'POST',
      body: JSON.stringify({ command, session_id: sessionId }),
    })
  }

  /** List terminal sessions */
  async listSessions(): Promise<{ sessions: ITerminalSession[] }> {
    return this.request<{ sessions: ITerminalSession[] }>('/terminal/sessions')
  }

  /** Get command history for a session */
  async getCommandHistory(
    sessionId: string
  ): Promise<{ history: ICommandRecord[] }> {
    return this.request<{ history: ICommandRecord[] }>(`/terminal/sessions/${sessionId}/history`)
  }

  /** Close a terminal session */
  async closeSession(sessionId: string): Promise<{ status: string; session_id: string }> {
    return this.request<{ status: string; session_id: string }>(`/terminal/sessions/${sessionId}`, {
      method: 'DELETE',
    })
  }

  // ── User whitelist ──────────────────────────────────────────────

  async listUserWhitelist(): Promise<{ entries: IWhitelistEntry[] }> {
    return this.request<{ entries: IWhitelistEntry[] }>('/terminal/whitelist/user')
  }

  async addUserWhitelist(commandPattern: string): Promise<IWhitelistEntry> {
    return this.request<IWhitelistEntry>('/terminal/whitelist/user', {
      method: 'POST',
      body: JSON.stringify({ command_pattern: commandPattern }),
    })
  }

  async deleteUserWhitelist(entryId: string): Promise<void> {
    await this.request<void>(`/terminal/whitelist/user/${entryId}`, {
      method: 'DELETE',
    })
  }

  // ── Global whitelist (admin) ────────────────────────────────────

  async listGlobalWhitelist(): Promise<{ entries: IWhitelistEntry[] }> {
    return this.request<{ entries: IWhitelistEntry[] }>('/terminal/whitelist/global')
  }

  async addGlobalWhitelist(commandPattern: string): Promise<IWhitelistEntry> {
    return this.request<IWhitelistEntry>('/terminal/whitelist/global', {
      method: 'POST',
      body: JSON.stringify({ command_pattern: commandPattern }),
    })
  }

  async deleteGlobalWhitelist(entryId: string): Promise<void> {
    await this.request<void>(`/terminal/whitelist/global/${entryId}`, {
      method: 'DELETE',
    })
  }

  // ── Blocklist (admin) ───────────────────────────────────────────

  async listBlocklist(): Promise<{ entries: IBlocklistEntry[] }> {
    return this.request<{ entries: IBlocklistEntry[] }>('/terminal/blocklist')
  }

  async addBlocklist(commandPattern: string, reason: string): Promise<IBlocklistEntry> {
    return this.request<IBlocklistEntry>('/terminal/blocklist', {
      method: 'POST',
      body: JSON.stringify({ command_pattern: commandPattern, reason }),
    })
  }

  async deleteBlocklist(entryId: string): Promise<void> {
    await this.request<void>(`/terminal/blocklist/${entryId}`, {
      method: 'DELETE',
    })
  }

  // ── Audit logs (admin) ──────────────────────────────────────────

  async listAuditLogs(params?: {
    user_id?: string
    session_id?: string
    terminal_mode?: string
    limit?: number
    offset?: number
  }): Promise<{ entries: IAuditLogEntry[]; total: number }> {
    const query = new URLSearchParams()
    if (params?.user_id) query.set('user_id', params.user_id)
    if (params?.session_id) query.set('session_id', params.session_id)
    if (params?.terminal_mode) query.set('terminal_mode', params.terminal_mode)
    if (params?.limit) query.set('limit', String(params.limit))
    if (params?.offset) query.set('offset', String(params.offset))
    const qs = query.toString() ? `?${query.toString()}` : ''
    return this.request<{ entries: IAuditLogEntry[]; total: number }>(`/terminal/audit-logs${qs}`)
  }

  // ── Approvals (admin) ───────────────────────────────────────────

  async listApprovals(status?: string): Promise<{ approvals: IApprovalEntry[]; total: number }> {
    const qs = status ? `?status=${encodeURIComponent(status)}` : ''
    return this.request<{ approvals: IApprovalEntry[]; total: number }>(`/terminal/approvals${qs}`)
  }

  async approveApproval(approvalId: string, note?: string): Promise<IApprovalEntry> {
    return this.request<IApprovalEntry>(`/terminal/approvals/${approvalId}/approve`, {
      method: 'POST',
      body: JSON.stringify({ note: note ?? '' }),
    })
  }

  async rejectApproval(approvalId: string, note?: string): Promise<IApprovalEntry> {
    return this.request<IApprovalEntry>(`/terminal/approvals/${approvalId}/reject`, {
      method: 'POST',
      body: JSON.stringify({ note: note ?? '' }),
    })
  }
}

export const terminalApi = new TerminalApiClient()

// Backward-compatible standalone function exports
export const createTerminalWsUrl = terminalApi.createTerminalWsUrl.bind(terminalApi)
export const executeCommand = terminalApi.executeCommand.bind(terminalApi)
export const listSessions = terminalApi.listSessions.bind(terminalApi)
export const getCommandHistory = terminalApi.getCommandHistory.bind(terminalApi)
