/**
 * API Client
 *
 * 用于连接远程 Server 的客户端
 */

export interface ClientConfig {
  /** 服务器地址 */
  baseUrl: string;
  /** 认证 token */
  token?: string;
  /** 请求超时 (ms) */
  timeout?: number;
}

export interface Session {
  id: string;
  name?: string;
  createdAt: string;
  updatedAt: string;
  status: string;
  messageCount: number;
}

export interface Message {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  timestamp: string;
}

export interface HealthStatus {
  status: string;
  timestamp: string;
  agent: {
    coreAvailable: boolean;
  };
  auth: {
    enabled: boolean;
    tokenCount: number;
  };
  stats: {
    sessions: number;
    websocket: { connections: number };
    sse: { connections: number };
  };
}

// ============ Command 相关 ============

export interface CommandInfo {
  name: string;
  description?: string;
  agent?: string;
  model?: string;
  subtask?: boolean;
  source: string;
  hasTemplate: boolean;
}

export interface CommandSearchResult {
  name: string;
  description?: string;
  source: string;
  score: number;
}

export interface CommandExecuteResult {
  prompt: string;
  agent?: string;
  model?: string;
  subtask?: boolean;
}

export interface CommandListResponse {
  commands: Array<{ name: string; description?: string; source: string }>;
  stats: { total: number; bySource: Record<string, number> };
}

// ============ Command CRUD 相关 ============

export interface CreateCommandInput {
  name: string;
  description?: string;
  template: string;
  agent?: string;
  model?: string;
  subtask?: boolean;
  scope: 'user' | 'project';
}

export interface UpdateCommandInput {
  description?: string;
  template?: string;
  agent?: string;
  model?: string;
  subtask?: boolean;
}

export interface CommandContent {
  name: string;
  description?: string;
  template: string;
  agent?: string;
  model?: string;
  subtask?: boolean;
  source: string;
  sourcePath?: string;
}

/**
 * API Client 类
 */
export class APIClient {
  private baseUrl: string;
  private token?: string;
  private timeout: number;

  constructor(config: ClientConfig) {
    this.baseUrl = config.baseUrl.replace(/\/$/, '');
    this.token = config.token;
    this.timeout = config.timeout || 30000;
  }

  /**
   * 发送 HTTP 请求
   */
  private async request<T>(
    method: string,
    path: string,
    body?: unknown
  ): Promise<T> {
    const url = `${this.baseUrl}${path}`;
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
    };

    if (this.token) {
      headers['Authorization'] = `Bearer ${this.token}`;
    }

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);

    try {
      const response = await fetch(url, {
        method,
        headers,
        body: body ? JSON.stringify(body) : undefined,
        signal: controller.signal,
      });

      clearTimeout(timeoutId);

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({ error: response.statusText })) as { error?: string };
        throw new Error(errorData.error || `HTTP ${response.status}`);
      }

      return response.json() as Promise<T>;
    } catch (error) {
      clearTimeout(timeoutId);
      if (error instanceof Error && error.name === 'AbortError') {
        throw new Error('Request timeout');
      }
      throw error;
    }
  }

  // ============================================================================
  // Health
  // ============================================================================

  async health(): Promise<HealthStatus> {
    return this.request('GET', '/health');
  }

  // ============================================================================
  // Sessions
  // ============================================================================

  async listSessions(): Promise<{ success: boolean; data: Session[] }> {
    return this.request('GET', '/api/sessions');
  }

  async createSession(name?: string): Promise<{ success: boolean; data: Session }> {
    return this.request('POST', '/api/sessions', { name });
  }

  async getSession(id: string): Promise<{ success: boolean; data: Session }> {
    return this.request('GET', `/api/sessions/${id}`);
  }

  async deleteSession(id: string): Promise<{ success: boolean }> {
    return this.request('DELETE', `/api/sessions/${id}`);
  }

  // ============================================================================
  // Messages
  // ============================================================================

  async getMessages(sessionId: string): Promise<{ success: boolean; data: Message[] }> {
    return this.request('GET', `/api/sessions/${sessionId}/messages`);
  }

  async sendMessage(
    sessionId: string,
    content: string
  ): Promise<{ success: boolean; data: Message }> {
    return this.request('POST', `/api/sessions/${sessionId}/messages`, { content });
  }

  // ============================================================================
  // WebSocket
  // ============================================================================

  /**
   * 创建 WebSocket 连接
   */
  connectWebSocket(sessionId: string): WebSocket {
    const wsUrl = this.baseUrl
      .replace(/^http/, 'ws')
      .concat(`/api/ws/${sessionId}`);

    const url = this.token
      ? `${wsUrl}?token=${encodeURIComponent(this.token)}`
      : wsUrl;

    return new WebSocket(url);
  }

  // ============================================================================
  // SSE
  // ============================================================================

  /**
   * 获取 SSE URL (用于外部 EventSource 连接)
   */
  getSSEUrl(sessionId: string): string {
    const sseUrl = `${this.baseUrl}/api/sessions/${sessionId}/events`;
    return this.token
      ? `${sseUrl}?token=${encodeURIComponent(this.token)}`
      : sseUrl;
  }

  // ============================================================================
  // Commands
  // ============================================================================

  async listCommands(): Promise<{ success: boolean; data: CommandListResponse }> {
    return this.request('GET', '/api/commands');
  }

  async getCommand(name: string): Promise<{ success: boolean; data: CommandInfo }> {
    return this.request('GET', `/api/commands/${encodeURIComponent(name)}`);
  }

  async executeCommand(
    name: string,
    args: string = ''
  ): Promise<{ success: boolean; data?: CommandExecuteResult; error?: string }> {
    return this.request('POST', `/api/commands/${encodeURIComponent(name)}/execute`, {
      arguments: args,
    });
  }

  async searchCommands(
    query: string,
    limit: number = 10
  ): Promise<{ success: boolean; data: CommandSearchResult[] }> {
    return this.request('POST', '/api/commands/search', { query, limit });
  }

  async reloadCommands(): Promise<{
    success: boolean;
    data: { message: string; stats: { total: number; bySource: Record<string, number> } };
  }> {
    return this.request('POST', '/api/commands/reload');
  }

  // ============================================================================
  // Commands CRUD
  // ============================================================================

  async createCommand(
    input: CreateCommandInput
  ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> {
    return this.request('POST', '/api/commands', input);
  }

  async getCommandContent(
    name: string
  ): Promise<{ success: boolean; data?: CommandContent; error?: string }> {
    return this.request('GET', `/api/commands/${encodeURIComponent(name)}/content`);
  }

  async updateCommand(
    name: string,
    input: UpdateCommandInput
  ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> {
    return this.request('PUT', `/api/commands/${encodeURIComponent(name)}`, input);
  }

  async deleteCommand(
    name: string
  ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> {
    return this.request('DELETE', `/api/commands/${encodeURIComponent(name)}`);
  }
}

/**
 * 创建 API Client
 */
export function createClient(config: ClientConfig): APIClient {
  return new APIClient(config);
}
