/**
 * API 客户端
 * 使用 fetch API 进行 HTTP 请求
 * 支持请求/响应拦截器
 * 支持主动刷新 token（快过期时自动刷新）
 */

import AsyncStorage from '@react-native-async-storage/async-storage';
import { CommonActions } from '@react-navigation/native';
import Constants from 'expo-constants';
import { Platform } from 'react-native';

// 生产地址 https://bbs.littlelan.cn
const getBaseUrl = () => {
  const configuredBaseUrl = Constants.expoConfig?.extra?.apiBaseUrl;
  if (typeof configuredBaseUrl === 'string' && configuredBaseUrl.trim().length > 0) {
    return configuredBaseUrl;
  }
  return 'https://bbs.littlelan.cn/api/v1';
};

const BASE_URL = getBaseUrl();
const SSE_URL = `${BASE_URL.replace(/\/+$/, '')}/realtime/sse`;

// Token 存储键
const TOKEN_KEY = 'auth_token';
const REFRESH_TOKEN_KEY = 'refresh_token';

// Token 提前刷新阈值（秒）：提前 5 分钟刷新
const TOKEN_REFRESH_THRESHOLD_SECONDS = 5 * 60;

// API 响应格式
export interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

// 分页响应格式
export interface PaginatedData<T> {
  list: T[];
  total: number;
  page: number;
  page_size: number;
  total_pages: number;
}

// 错误类型
export class ApiError extends Error {
  code: number;
  message: string;

  constructor(code: number, message: string) {
    super(message);
    this.code = code;
    this.message = message;
    this.name = 'ApiError';
  }
}

// JWT Payload 结构
interface JwtPayload {
  user_id: string;
  username: string;
  exp?: number;
  iat?: number;
  iss?: string;
}

// API 客户端类
class ApiClient {
  private baseUrl: string;
  private navigation: any = null;
  // 刷新锁：防止并发刷新
  private refreshLock: Promise<boolean> | null = null;

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

  // 设置导航对象（用于处理401跳转）
  setNavigation(navigation: any) {
    this.navigation = navigation;
  }

  // 解析 JWT token 获取 payload
  private parseJwt(token: string): JwtPayload | null {
    try {
      const parts = token.split('.');
      if (parts.length !== 3) {
        return null;
      }
      // React Native/Expo 环境使用 atob
      const payload = JSON.parse(atob(parts[1]));
      return payload as JwtPayload;
    } catch {
      return null;
    }
  }

  // 检查 token 是否快过期（返回 true 表示需要刷新）
  private isTokenExpiringSoon(token: string): boolean {
    const payload = this.parseJwt(token);
    if (!payload || !payload.exp) {
      return false;
    }
    const now = Math.floor(Date.now() / 1000);
    const remaining = payload.exp - now;
    // 剩余时间小于阈值时需要刷新
    return remaining < TOKEN_REFRESH_THRESHOLD_SECONDS && remaining > 0;
  }

  // 获取 token
  async getToken(): Promise<string | null> {
    try {
      return await AsyncStorage.getItem(TOKEN_KEY);
    } catch (error) {
      console.error('获取token失败:', error);
      return null;
    }
  }

  // 保存 token
  async setToken(token: string): Promise<void> {
    try {
      await AsyncStorage.setItem(TOKEN_KEY, token);
    } catch (error) {
      console.error('保存token失败:', error);
    }
  }

  // 获取刷新 token
  async getRefreshToken(): Promise<string | null> {
    try {
      return await AsyncStorage.getItem(REFRESH_TOKEN_KEY);
    } catch (error) {
      console.error('获取刷新token失败:', error);
      return null;
    }
  }

  // 保存刷新 token
  async setRefreshToken(token: string): Promise<void> {
    try {
      await AsyncStorage.setItem(REFRESH_TOKEN_KEY, token);
    } catch (error) {
      console.error('保存刷新token失败:', error);
    }
  }

  // 清除 token
  async clearToken(): Promise<void> {
    try {
      await AsyncStorage.multiRemove([TOKEN_KEY, REFRESH_TOKEN_KEY]);
    } catch (error) {
      console.error('清除token失败:', error);
    }
  }

  // 统一请求方法
  private async request<T>(
    method: string,
    path: string,
    params?: Record<string, any>,
    body?: any
  ): Promise<ApiResponse<T>> {
    const url = new URL(`${this.baseUrl}${path}`);
    
    // 添加查询参数
    if (params) {
      Object.keys(params).forEach(key => {
        if (params[key] !== undefined && params[key] !== null) {
          url.searchParams.append(key, String(params[key]));
        }
      });
    }

    // 构建请求头
    const headers: HeadersInit = {
      'Content-Type': 'application/json',
    };

    // 添加认证 token（主动刷新快过期的 token）
    const token = await this.getToken();
    if (token) {
      // 检查 token 是否快过期，如果是则主动刷新
      if (this.isTokenExpiringSoon(token)) {
        const refreshed = await this.refreshToken();
        if (!refreshed) {
          // 刷新失败，清除 token 并跳转登录
          await this.clearToken();
          if (this.navigation) {
            this.navigation.dispatch(
              CommonActions.reset({
                index: 0,
                routes: [{ name: 'Login' }],
              })
            );
          }
          throw new ApiError(401, '登录已过期，请重新登录');
        }
        // 刷新成功，使用新 token
        const newToken = await this.getToken();
        if (newToken) {
          headers['Authorization'] = `Bearer ${newToken}`;
        }
      } else {
        headers['Authorization'] = `Bearer ${token}`;
      }
    }

    // 构建请求配置
    const config: RequestInit = {
      method,
      headers,
    };

    // 添加请求体
    if (body && method !== 'GET') {
      config.body = JSON.stringify(body);
    }

    try {
      const response = await fetch(url.toString(), config);
      
      // 处理 401 未授权
      if (response.status === 401) {
        // 尝试刷新 token
        const refreshed = await this.refreshToken();
        if (!refreshed) {
          // 刷新失败，清除 token 并跳转登录
          await this.clearToken();
          if (this.navigation) {
            this.navigation.dispatch(
              CommonActions.reset({
                index: 0,
                routes: [{ name: 'Login' }],
              })
            );
          }
          throw new ApiError(401, '登录已过期，请重新登录');
        }
        
        // 刷新成功后重试请求
        return this.request(method, path, params, body);
      }

      // 解析响应（兼容非 JSON 返回，避免 SyntaxError 被误判为网络错误）
      const contentType = response.headers.get('content-type') || '';
      let parsedBody: any = null;
      let rawText = '';

      if (contentType.includes('application/json')) {
        parsedBody = await response.json();
      } else {
        rawText = await response.text();
        if (rawText) {
          try {
            parsedBody = JSON.parse(rawText);
          } catch {
            parsedBody = null;
          }
        }
      }

      // 优先处理标准 API 结构
      if (parsedBody && typeof parsedBody === 'object' && 'code' in parsedBody) {
        const data = parsedBody as ApiResponse<T>;
        if (data.code !== 0) {
          throw new ApiError(data.code, data.message || '请求失败');
        }
        return data;
      }

      // 非标准结构：先按 HTTP 状态处理失败
      if (!response.ok) {
        const fallbackMessage = rawText || response.statusText || `请求失败(${response.status})`;
        throw new ApiError(response.status, fallbackMessage);
      }

      // 非标准结构但 HTTP 成功：兜底为成功响应（兼容部分纯文本成功接口）
      return {
        code: 0,
        message: 'success',
        data: (parsedBody as T) ?? (undefined as T),
      };
    } catch (error) {
      // 如果是 ApiError，直接抛出
      if (error instanceof ApiError) {
        throw error;
      }
      
      // 网络错误
      console.error('API请求失败:', error);
      throw new ApiError(500, '网络请求失败，请检查网络连接');
    }
  }

  // 刷新 token（带锁，防止并发刷新）
  private async refreshToken(): Promise<boolean> {
    // 如果已有刷新操作正在进行，等待其完成
    if (this.refreshLock) {
      return this.refreshLock;
    }

    // 创建刷新锁
    this.refreshLock = this.doRefreshToken();

    try {
      const result = await this.refreshLock;
      return result;
    } finally {
      // 释放刷新锁
      this.refreshLock = null;
    }
  }

  // 实际执行刷新 token
  private async doRefreshToken(): Promise<boolean> {
    try {
      const refreshToken = await this.getRefreshToken();
      if (!refreshToken) {
        return false;
      }

      const response = await fetch(`${this.baseUrl}/auth/refresh`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          refresh_token: refreshToken,
        }),
      });

      if (!response.ok) {
        return false;
      }

      const data = await response.json();
      if (data.code === 0 && data.data?.token) {
        await this.setToken(data.data.token);
        // 后端返回refresh_token (snake_case)，兼容两种命名
        if (data.data.refresh_token || data.data.refreshToken) {
          await this.setRefreshToken(data.data.refresh_token || data.data.refreshToken);
        }
        return true;
      }

      return false;
    } catch (error) {
      console.error('刷新token失败:', error);
      return false;
    }
  }

  // GET 请求
  async get<T>(path: string, params?: Record<string, any>): Promise<ApiResponse<T>> {
    return this.request<T>('GET', path, params);
  }

  // POST 请求
  async post<T>(path: string, body?: any): Promise<ApiResponse<T>> {
    return this.request<T>('POST', path, undefined, body);
  }

  // PUT 请求
  async put<T>(path: string, body?: any): Promise<ApiResponse<T>> {
    return this.request<T>('PUT', path, undefined, body);
  }

  // DELETE 请求
  async delete<T>(path: string, body?: any): Promise<ApiResponse<T>> {
    return this.request<T>('DELETE', path, undefined, body);
  }

  // 上传文件
  async upload<T>(
    path: string,
    file: { uri: string; name: string; type: string },
    additionalData?: Record<string, string>
  ): Promise<ApiResponse<T>> {
    const formData = new FormData();
    
    // 添加文件（使用 image 字段名）
    // Web 端需要 append Blob/File；原生端可以直接传 { uri, name, type }。
    if (Platform.OS === 'web') {
      const fileResponse = await fetch(file.uri);
      const blob = await fileResponse.blob();
      const uploadFile = new File([blob], file.name, { type: file.type || blob.type || 'application/octet-stream' });
      formData.append('image', uploadFile);
    } else {
      formData.append('image', {
        uri: file.uri,
        name: file.name,
        type: file.type,
      } as any);
    }

    // 添加额外数据
    if (additionalData) {
      Object.keys(additionalData).forEach(key => {
        formData.append(key, additionalData[key]);
      });
    }

    // 获取 token 并检查是否需要刷新
    const token = await this.getToken();
    const headers: HeadersInit = {};
    if (token) {
      // 检查 token 是否快过期
      if (this.isTokenExpiringSoon(token)) {
        const refreshed = await this.refreshToken();
        if (refreshed) {
          const newToken = await this.getToken();
          if (newToken) {
            headers['Authorization'] = `Bearer ${newToken}`;
          }
        }
      } else {
        headers['Authorization'] = `Bearer ${token}`;
      }
    }

    const response = await fetch(`${this.baseUrl}${path}`, {
      method: 'POST',
      headers,
      body: formData,
    });

    const data: ApiResponse<T> = await response.json();
    
    if (data.code !== 0) {
      throw new ApiError(data.code, data.message);
    }

    return data;
  }
}

// 导出 API 客户端实例
export const api = new ApiClient(BASE_URL);

export { SSE_URL, TOKEN_KEY, REFRESH_TOKEN_KEY };
