/**
 * SSE 客户端类
 * 用于与后端 SSE 服务进行对接，实现异步任务的实时进度推送
 * 使用 fetch API 实现，支持自定义 Header（包括鉴权）
 */

import { getToken, formatToken } from "@/utils/auth";

export interface SseMessage {
  type: string;
  event: string;
  userId: string;
  data: any;
  timestamp: string;
}

export interface ProjectInitTaskVO {
  taskId: string;
  status: string;
  statusDesc: string;
  progress: number;
  progressMessage: string;
  originalFilename: string;
  createTime: string;
  startTime: string;
  completeTime: string;
  result?: any;
  errorMessage?: string;
}

/** 风险评估任务VO */
export interface RiskAssessTaskVO {
  taskId: string;
  userId: string;
  projectId: string;
  projectName?: string;
  status: string;
  statusDesc: string;
  progress: number;
  progressMessage: string;
  createTime: string;
  startTime?: string;
  completeTime?: string;
  result?: any;
  errorMessage?: string;
}

type SseEventCallback = (data: any, message?: SseMessage) => void;

export class SseClient {
  private userId: string;
  private abortController: AbortController | null = null;
  private listeners: Map<string, SseEventCallback[]> = new Map();
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 3;
  private reconnectDelay = 3000;
  private isManualClose = false;
  private _isConnected = false;

  constructor(userId: string) {
    this.userId = userId;
  }

  /**
   * 获取鉴权 Header
   */
  private getAuthHeaders(): Record<string, string> {
    const headers: Record<string, string> = {
      Accept: "text/event-stream",
      "Cache-Control": "no-cache"
    };

    const tokenData = getToken();
    if (tokenData?.accessToken) {
      headers["Authorization"] = formatToken(tokenData.accessToken);
    }

    return headers;
  }

  /**
   * 建立 SSE 连接（使用 fetch API 支持自定义 Header）
   */
  async connect(): Promise<void> {
    if (this.abortController) {
      console.warn("SSE 连接已存在");
      return;
    }

    this.isManualClose = false;
    this.abortController = new AbortController();
    const url = `/api/v1/sse/connect/${this.userId}`;
    console.log("正在建立 SSE 连接...", url);

    try {
      const response = await fetch(url, {
        method: "GET",
        headers: this.getAuthHeaders(),
        signal: this.abortController.signal
      });

      if (!response.ok) {
        throw new Error(
          `SSE 连接失败: ${response.status} ${response.statusText}`
        );
      }

      if (!response.body) {
        throw new Error("SSE 响应无 body");
      }

      this._isConnected = true;
      this.reconnectAttempts = 0;

      // 读取 SSE 流
      const reader = response.body.getReader();
      const decoder = new TextDecoder();
      let buffer = "";

      while (true) {
        const { done, value } = await reader.read();

        if (done) {
          console.log("SSE 流结束");
          break;
        }

        buffer += decoder.decode(value, { stream: true });

        // 解析 SSE 消息（以双换行分隔）
        const messages = buffer.split("\n\n");
        buffer = messages.pop() || ""; // 保留未完成的消息

        for (const msg of messages) {
          if (msg.trim()) {
            this.parseAndDispatch(msg);
          }
        }
      }
    } catch (error: any) {
      if (error.name === "AbortError") {
        console.log("SSE 连接已取消");
        return;
      }

      console.error("SSE 连接错误:", error);
      this._isConnected = false;
      this.emit("connection-error", error);

      // 自动重连
      if (
        !this.isManualClose &&
        this.reconnectAttempts < this.maxReconnectAttempts
      ) {
        this.reconnectAttempts++;
        console.log(
          `SSE 将在 ${this.reconnectDelay}ms 后重连 (第 ${this.reconnectAttempts} 次)`
        );
        setTimeout(() => {
          this.close();
          this.connect();
        }, this.reconnectDelay);
      } else if (this.reconnectAttempts >= this.maxReconnectAttempts) {
        console.error("SSE 重连次数已达上限");
        this.emit("max-reconnect-reached", null);
      }
    }
  }

  /**
   * 解析并分发 SSE 消息
   */
  private parseAndDispatch(rawMessage: string): void {
    const lines = rawMessage.split("\n");
    let eventName = "message";
    let data = "";

    for (const line of lines) {
      if (line.startsWith("event:")) {
        eventName = line.slice(6).trim();
      } else if (line.startsWith("data:")) {
        data = line.slice(5).trim();
      }
    }

    if (!data) return;

    try {
      const message = JSON.parse(data) as SseMessage;

      // 根据事件名称分发
      switch (eventName) {
        case "connected":
          console.log("SSE 连接成功:", message);
          this.emit("connected", message.data, message);
          break;
        case "submitted":
          console.log("任务已提交:", message);
          if (message.type === "project-init") {
            this.emit("project-init-submitted", message.data, message);
          } else if (message.type === "risk-assess") {
            this.emit("risk-assess-submitted", message.data, message);
          }
          break;
        case "progress":
          if (message.type === "project-init") {
            this.emit("project-init-progress", message.data, message);
          } else if (message.type === "risk-assess") {
            this.emit("risk-assess-progress", message.data, message);
          }
          break;
        case "complete":
          if (message.type === "project-init") {
            this.emit("project-init-complete", message.data, message);
          } else if (message.type === "risk-assess") {
            this.emit("risk-assess-complete", message.data, message);
          }
          break;
        case "error":
          console.error("SSE 错误事件:", message);
          if (message.type === "project-init") {
            this.emit("project-init-error", message.data, message);
          } else if (message.type === "risk-assess") {
            this.emit("risk-assess-error", message.data, message);
          }
          this.emit("error", message.data, message);
          break;
        default:
          console.log("SSE 未知事件:", eventName, message);
      }
    } catch (e) {
      console.error("SSE 消息解析失败:", data, e);
    }
  }

  /**
   * 提交项目初始化任务（SSE 方式）
   */
  async submitProjectInitTask(
    file: File
  ): Promise<{ code: number; data?: { taskId: string }; message?: string }> {
    const formData = new FormData();
    formData.append("userId", this.userId);
    formData.append("file", file);

    const tokenData = getToken();
    const headers: Record<string, string> = {};
    if (tokenData?.accessToken) {
      headers["Authorization"] = formatToken(tokenData.accessToken);
    }

    const response = await fetch("/api/v1/project-init/sse/submit-task", {
      method: "POST",
      headers,
      body: formData
    });

    return response.json();
  }

  /**
   * 关闭 SSE 连接
   */
  close(): void {
    this.isManualClose = true;
    this._isConnected = false;
    if (this.abortController) {
      this.abortController.abort();
      this.abortController = null;
      console.log("SSE 连接已关闭");
    }
  }

  /**
   * 注册事件监听
   */
  on(event: string, callback: SseEventCallback): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)!.push(callback);
  }

  /**
   * 移除事件监听
   */
  off(event: string, callback: SseEventCallback): void {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      const index = callbacks.indexOf(callback);
      if (index > -1) {
        callbacks.splice(index, 1);
      }
    }
  }

  /**
   * 触发事件
   */
  private emit(event: string, data: any, message?: SseMessage): void {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      callbacks.forEach(cb => cb(data, message));
    }
  }

  /**
   * 获取连接状态
   */
  get isConnected(): boolean {
    return this._isConnected;
  }

  /**
   * 获取用户ID
   */
  getUserId(): string {
    return this.userId;
  }
}

export default SseClient;
