import {
  DataClient,
  VideoStreamClient,
  BsdlParserClient,
  DDSClient,
  JtagClient,
  MatrixKeyClient,
  PowerClient,
  RemoteUpdateClient,
  TutorialClient,
  UDPClient,
  LogicAnalyzerClient,
  NetConfigClient,
  OscilloscopeApiClient,
  DebuggerClient,
  ExamClient,
  ResourceClient,
  HdmiVideoStreamClient,
} from "@/APIClient";
import router from "@/router";
import { HubConnectionBuilder } from "@microsoft/signalr";
import axios, { type AxiosInstance } from "axios";
import { isNull } from "lodash";

// 支持的客户端类型联合类型
type SupportedClient =
  | DataClient
  | VideoStreamClient
  | BsdlParserClient
  | DDSClient
  | JtagClient
  | MatrixKeyClient
  | PowerClient
  | RemoteUpdateClient
  | TutorialClient
  | LogicAnalyzerClient
  | UDPClient
  | NetConfigClient
  | OscilloscopeApiClient
  | DebuggerClient
  | ExamClient
  | ResourceClient
  | HdmiVideoStreamClient;

export class AuthManager {
  // 存储token到localStorage
  public static setToken(token: string): void {
    localStorage.setItem("authToken", token);
  }

  // 从localStorage获取token
  public static getToken(): string | null {
    return localStorage.getItem("authToken");
  }

  // 清除token
  public static clearToken(): void {
    localStorage.removeItem("authToken");
  }

  // 检查是否已认证
  public static async isAuthenticated(): Promise<boolean> {
    return await AuthManager.verifyToken();
  }

  // 通用的为HTTP请求添加Authorization header的方法
  public static addAuthHeader(client: SupportedClient): void {
    const token = AuthManager.getToken();
    if (token) {
      // 创建一个自定义的 http 对象，包装原有的 fetch 方法
      const customHttp = {
        fetch: (url: RequestInfo, init?: RequestInit) => {
          if (!init) init = {};
          if (!init.headers) init.headers = {};

          // 添加Authorization header
          if (typeof init.headers === "object" && init.headers !== null) {
            (init.headers as any)["Authorization"] = `Bearer ${token}`;
          }

          // 使用全局 fetch 或 window.fetch
          return (window as any).fetch(url, init);
        },
      };

      // 重新构造客户端，传入自定义的 http 对象
      const ClientClass = client.constructor as new (
        baseUrl?: string,
        http?: any,
      ) => SupportedClient;
      const newClient = new ClientClass(undefined, customHttp);

      // 将新客户端的属性复制到原客户端（这是一个 workaround）
      // 更好的做法是返回新的客户端实例
      Object.setPrototypeOf(client, Object.getPrototypeOf(newClient));
      Object.assign(client, newClient);
    }
  }

  // 私有方法：创建带认证的HTTP客户端
  private static createAuthenticatedHttp() {
    const token = AuthManager.getToken();
    if (!token) {
      return null;
    }

    return {
      fetch: (url: RequestInfo, init?: RequestInit) => {
        if (!init) init = {};
        if (!init.headers) init.headers = {};

        if (typeof init.headers === "object" && init.headers !== null) {
          (init.headers as any)["Authorization"] = `Bearer ${token}`;
        }

        return (window as any).fetch(url, init);
      },
    };
  }

  // 私有方法：创建带认证的Axios实例
  private static createAuthenticatedAxiosInstance(): AxiosInstance | null {
    const token = AuthManager.getToken();
    if (!token) return null;

    const instance = axios.create();
    instance.interceptors.request.use((config) => {
      config.headers = config.headers || {};
      (config.headers as any)["Authorization"] = `Bearer ${token}`;
      return config;
    });
    return instance;
  }

  // 通用的创建已认证客户端的方法（使用泛型）
  public static createAuthenticatedClient<T extends SupportedClient>(
    ClientClass: new (baseUrl?: string, instance?: AxiosInstance) => T,
  ): T {
    const axiosInstance = AuthManager.createAuthenticatedAxiosInstance();
    return axiosInstance
      ? new ClientClass(undefined, axiosInstance)
      : new ClientClass();
  }

  // 便捷方法：创建已配置认证的各种客户端
  public static createAuthenticatedDataClient(): DataClient {
    return AuthManager.createAuthenticatedClient(DataClient);
  }

  public static createAuthenticatedVideoStreamClient(): VideoStreamClient {
    return AuthManager.createAuthenticatedClient(VideoStreamClient);
  }

  public static createAuthenticatedBsdlParserClient(): BsdlParserClient {
    return AuthManager.createAuthenticatedClient(BsdlParserClient);
  }

  public static createAuthenticatedDDSClient(): DDSClient {
    return AuthManager.createAuthenticatedClient(DDSClient);
  }

  public static createAuthenticatedJtagClient(): JtagClient {
    return AuthManager.createAuthenticatedClient(JtagClient);
  }

  public static createAuthenticatedMatrixKeyClient(): MatrixKeyClient {
    return AuthManager.createAuthenticatedClient(MatrixKeyClient);
  }

  public static createAuthenticatedPowerClient(): PowerClient {
    return AuthManager.createAuthenticatedClient(PowerClient);
  }

  public static createAuthenticatedRemoteUpdateClient(): RemoteUpdateClient {
    return AuthManager.createAuthenticatedClient(RemoteUpdateClient);
  }

  public static createAuthenticatedTutorialClient(): TutorialClient {
    return AuthManager.createAuthenticatedClient(TutorialClient);
  }

  public static createAuthenticatedUDPClient(): UDPClient {
    return AuthManager.createAuthenticatedClient(UDPClient);
  }

  public static createAuthenticatedLogicAnalyzerClient(): LogicAnalyzerClient {
    return AuthManager.createAuthenticatedClient(LogicAnalyzerClient);
  }

  public static createAuthenticatedNetConfigClient(): NetConfigClient {
    return AuthManager.createAuthenticatedClient(NetConfigClient);
  }

  public static createAuthenticatedOscilloscopeApiClient(): OscilloscopeApiClient {
    return AuthManager.createAuthenticatedClient(OscilloscopeApiClient);
  }

  public static createAuthenticatedDebuggerClient(): DebuggerClient {
    return AuthManager.createAuthenticatedClient(DebuggerClient);
  }

  public static createAuthenticatedExamClient(): ExamClient {
    return AuthManager.createAuthenticatedClient(ExamClient);
  }

  public static createAuthenticatedResourceClient(): ResourceClient {
    return AuthManager.createAuthenticatedClient(ResourceClient);
  }

  public static createAuthenticatedHdmiVideoStreamClient(): HdmiVideoStreamClient {
    return AuthManager.createAuthenticatedClient(HdmiVideoStreamClient);
  }

  public static createAuthenticatedJtagHubConnection() {
    return new HubConnectionBuilder()
      .withUrl("http://127.0.0.1:5000/hubs/JtagHub", {
        accessTokenFactory: () => this.getToken() ?? "",
      })
      .withAutomaticReconnect()
      .build();
  }

  public static createAuthenticatedProgressHubConnection() {
    return new HubConnectionBuilder()
      .withUrl("http://127.0.0.1:5000/hubs/ProgressHub", {
        accessTokenFactory: () => this.getToken() ?? "",
      })
      .withAutomaticReconnect()
      .build();
  }

  // 登录函数
  public static async login(
    username: string,
    password: string,
  ): Promise<boolean> {
    try {
      const client = new DataClient();
      const token = await client.login(username, password);

      if (token) {
        AuthManager.setToken(token);

        // 验证token
        const authClient = AuthManager.createAuthenticatedDataClient();
        await authClient.testAuth();

        return true;
      }
      return false;
    } catch (error) {
      AuthManager.clearToken();
      throw error;
    }
  }

  // 登出函数
  public static logout(): void {
    AuthManager.clearToken();
  }

  // 验证当前token是否有效
  public static async verifyToken(): Promise<boolean> {
    try {
      const token = AuthManager.getToken();
      if (!token) {
        return false;
      }

      const client = AuthManager.createAuthenticatedDataClient();
      await client.testAuth();
      return true;
    } catch (error) {
      AuthManager.clearToken();
      return false;
    }
  }

  // 验证管理员权限
  public static async verifyAdminAuth(): Promise<boolean> {
    try {
      const token = AuthManager.getToken();
      if (!token) {
        return false;
      }

      const client = AuthManager.createAuthenticatedDataClient();
      await client.testAdminAuth();
      return true;
    } catch (error) {
      // 只有在token完全无效的情况下才清除token
      // 401错误表示token有效但权限不足，不应清除token
      if (error && typeof error === "object" && "status" in error) {
        // 如果是403 (Forbidden) 或401 (Unauthorized)，说明token有效但权限不足
        if (error.status === 401 || error.status === 403) {
          return false;
        }
        // 其他状态码可能表示token无效，清除token
        AuthManager.clearToken();
      } else {
        // 网络错误等，不清除token
        console.error("管理员权限验证失败:", error);
      }
      return false;
    }
  }

  // 检查客户端是否已配置认证
  public static isClientAuthenticated(client: SupportedClient): boolean {
    const token = AuthManager.getToken();
    return !!token;
  }
}
