/* eslint-disable @typescript-eslint/no-explicit-any */

// Token 内存缓存
const tokenCache = new Map<string, { token: string; expiresAt: number }>();

export interface OpenListFile {
  name: string;
  size: number;
  is_dir: boolean;
  modified: string;
  sign?: string; // 临时下载签名
  raw_url?: string; // 完整下载链接
  thumb?: string;
  type: number;
  path?: string;
}

export interface OpenListListResponse {
  code: number;
  message: string;
  data: {
    content: OpenListFile[];
    total: number;
    readme: string;
    write: boolean;
  };
}

export interface OpenListGetResponse {
  code: number;
  message: string;
  data: OpenListFile;
}

export class OpenListClient {
  private token = '';

  constructor(
    private baseURL: string,
    private username: string,
    private password: string
  ) {}

  /**
   * 使用账号密码登录获取Token
   */
  static async login(
    baseURL: string,
    username: string,
    password: string
  ): Promise<string> {
    const response = await fetch(`${baseURL}/api/auth/login`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        username,
        password,
      }),
    });

    if (!response.ok) {
      throw new Error(`OpenList 登录失败: ${response.status}`);
    }

    const data = await response.json();
    if (data.code !== 200 || !data.data?.token) {
      throw new Error('OpenList 登录失败: 未获取到Token');
    }

    return data.data.token;
  }

  /**
   * 获取缓存的 Token 或重新登录
   */
  private async getToken(): Promise<string> {
    const cacheKey = `${this.baseURL}:${this.username}`;
    const cached = tokenCache.get(cacheKey);

    // 如果有缓存且未过期，直接返回
    if (cached && cached.expiresAt > Date.now()) {
      this.token = cached.token;
      return this.token;
    }

    // 否则重新登录
    console.log('[OpenListClient] Token 不存在或已过期，重新登录');
    this.token = await OpenListClient.login(
      this.baseURL,
      this.username,
      this.password
    );

    // 缓存 Token，设置 1 小时过期
    tokenCache.set(cacheKey, {
      token: this.token,
      expiresAt: Date.now() + 60 * 60 * 1000,
    });

    console.log('[OpenListClient] 登录成功，Token 已缓存');
    return this.token;
  }

  /**
   * 清除 Token 缓存（当 Token 失效时调用）
   */
  private clearTokenCache(): void {
    const cacheKey = `${this.baseURL}:${this.username}`;
    tokenCache.delete(cacheKey);
    console.log('[OpenListClient] Token 缓存已清除');
  }

  /**
   * 执行请求，如果401则清除缓存并重新登录后重试
   */
  private async fetchWithRetry(
    url: string,
    options: RequestInit,
    retried = false
  ): Promise<Response> {
    // 获取 Token
    const token = await this.getToken();

    // 更新请求头中的 Token
    const requestOptions = {
      ...options,
      headers: {
        ...options.headers,
        Authorization: token,
      },
    };

    const response = await fetch(url, requestOptions);

    // 检查 HTTP status 401
    if (response.status === 401 && !retried) {
      console.log('[OpenListClient] 收到 HTTP 401，清除 Token 缓存并重试');
      this.clearTokenCache();
      return this.fetchWithRetry(url, options, true);
    }

    // 检查响应体中的 code 字段（OpenList 的 Token 过期时 HTTP status 是 200，但 code 是 401）
    if (response.ok && !retried) {
      try {
        // 克隆响应以便读取 JSON
        const clonedResponse = response.clone();
        const data = await clonedResponse.json();

        if (data.code === 401) {
          console.log('[OpenListClient] 响应体 code 为 401，Token 已过期，清除缓存并重试');
          this.clearTokenCache();
          return this.fetchWithRetry(url, options, true);
        }
      } catch (error) {
        // 如果解析 JSON 失败，忽略错误，返回原始响应
        console.warn('[OpenListClient] 解析响应 JSON 失败:', error);
      }
    }

    return response;
  }

  private async getHeaders() {
    const token = await this.getToken();
    return {
      Authorization: token, // 不带 bearer
      'Content-Type': 'application/json',
    };
  }

  // 列出目录
  async listDirectory(
    path: string,
    page = 1,
    perPage = 100,
    refresh = false
  ): Promise<OpenListListResponse> {
    const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/list`, {
      method: 'POST',
      headers: await this.getHeaders(),
      body: JSON.stringify({
        path,
        password: '',
        refresh,
        page,
        per_page: perPage,
      }),
    });

    if (!response.ok) {
      throw new Error(`OpenList API 错误: ${response.status}`);
    }

    return response.json();
  }

  // 获取文件信息
  async getFile(path: string): Promise<OpenListGetResponse> {
    const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/get`, {
      method: 'POST',
      headers: await this.getHeaders(),
      body: JSON.stringify({
        path,
        password: '',
      }),
    });

    if (!response.ok) {
      throw new Error(`OpenList API 错误: ${response.status}`);
    }

    return response.json();
  }

  // 上传文件
  async uploadFile(path: string, content: string): Promise<void> {
    const token = await this.getToken();
    const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/put`, {
      method: 'PUT',
      headers: {
        Authorization: token,
        'Content-Type': 'text/plain; charset=utf-8',
        'File-Path': encodeURIComponent(path),
        'As-Task': 'false',
      },
      body: content,
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`OpenList 上传失败: ${response.status} - ${errorText}`);
    }

    // 上传成功后刷新目录缓存
    const dir = path.substring(0, path.lastIndexOf('/')) || '/';
    await this.refreshDirectory(dir);
  }

  // 刷新目录缓存
  async refreshDirectory(path: string): Promise<void> {
    try {
      const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/list`, {
        method: 'POST',
        headers: await this.getHeaders(),
        body: JSON.stringify({
          path,
          password: '',
          refresh: true,
          page: 1,
          per_page: 1,
        }),
      });

      if (!response.ok) {
        console.warn(`刷新目录缓存失败: ${response.status}`);
      }
    } catch (error) {
      console.warn('刷新目录缓存失败:', error);
    }
  }

  // 删除文件
  async deleteFile(path: string): Promise<void> {
    const dir = path.substring(0, path.lastIndexOf('/')) || '/';
    const fileName = path.substring(path.lastIndexOf('/') + 1);

    const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/remove`, {
      method: 'POST',
      headers: await this.getHeaders(),
      body: JSON.stringify({
        names: [fileName],
        dir: dir,
      }),
    });

    if (!response.ok) {
      throw new Error(`OpenList 删除失败: ${response.status}`);
    }
  }

  // 获取视频预览流
  async getVideoPreview(path: string): Promise<any> {
    const response = await this.fetchWithRetry(`${this.baseURL}/api/fs/other`, {
      method: 'POST',
      headers: await this.getHeaders(),
      body: JSON.stringify({
        path: path,
        method: 'video_preview',
        password: '',
      }),
    });

    if (!response.ok) {
      throw new Error(`视频预览请求失败: ${response.status}`);
    }

    const data = await response.json();

    if (data.code !== 200) {
      throw new Error(`视频预览失败: ${data.message}`);
    }

    return data;
  }

  // 检查连通性
  async checkConnectivity(): Promise<{ success: boolean; message: string }> {
    try {
      const response = await this.fetchWithRetry(`${this.baseURL}/api/me`, {
        method: 'GET',
        headers: await this.getHeaders(),
      });

      if (response.status !== 200) {
        return {
          success: false,
          message: `HTTP 状态码错误: ${response.status}`,
        };
      }

      const data = await response.json();

      if (data.code !== 200) {
        return {
          success: false,
          message: `响应码错误: ${data.code}`,
        };
      }

      return {
        success: true,
        message: '连接成功',
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : '连接失败',
      };
    }
  }
}
