import axios, { AxiosError, AxiosResponse, AxiosRequestConfig } from 'axios';
import { buildLoginRedirectUrl, getCurrentRelativePath } from './auth-redirect';
import { toast } from './toast';
import { getCurrentLocale } from './i18n';
import { getTranslations } from '@/locales';

// ==================== 类型定义 ====================

/**
 * API 成功响应格式
 */
export interface ApiResponse<T = any> {
  success: boolean;
  data: T;
  message?: string;
  timestamp: string;
  path?: string;
}

/**
 * API 错误响应格式
 */
export interface ApiErrorResponse {
  success: false;
  error: {
    code: string;
    message: string;
    details?: any;
    field?: string;
    errors?: FieldError[];
  };
  timestamp: string;
  path: string;
  method: string;
  statusCode: number;
}

/**
 * 字段验证错误
 */
export interface FieldError {
  field: string;
  message: string;
  value?: any;
  constraint?: string;
}

/**
 * 分页数据
 */
export interface PaginatedData<T> {
  items: T[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
  hasNext: boolean;
  hasPrev: boolean;
}

// ==================== 自定义错误类 ====================

/**
 * API 客户端错误类
 * 
 * 包装后端返回的错误，提供类型安全的错误处理
 */
export class ApiClientError extends Error {
  public readonly code: string;
  public readonly statusCode: number;
  public readonly details?: any;
  public readonly field?: string;
  public readonly errors?: FieldError[];
  public readonly path?: string;
  public readonly method?: string;

  constructor(apiError: ApiErrorResponse) {
    super(apiError.error.message);
    this.name = 'ApiClientError';
    this.code = apiError.error.code;
    this.statusCode = apiError.statusCode;
    this.details = apiError.error.details;
    this.field = apiError.error.field;
    this.errors = apiError.error.errors;
    this.path = apiError.path;
    this.method = apiError.method;
  }

  /**
   * 是否是验证错误
   */
  isValidationError(): boolean {
    return this.code === 'VALIDATION_ERROR';
  }

  /**
   * 是否是未授权错误
   */
  isUnauthorized(): boolean {
    return this.statusCode === 401;
  }

  /**
   * 是否是无权限错误
   */
  isForbidden(): boolean {
    return this.statusCode === 403;
  }

  /**
   * 是否是资源不存在错误
   */
  isNotFound(): boolean {
    return this.statusCode === 404;
  }

  /**
   * 是否是冲突错误
   */
  isConflict(): boolean {
    return this.statusCode === 409;
  }

  /**
   * 获取指定字段的错误消息
   */
  getFieldError(field: string): string | undefined {
    return this.errors?.find((e) => e.field === field)?.message;
  }

  /**
   * 获取所有字段错误，返回对象格式 { field: message }
   */
  getAllFieldErrors(): Record<string, string> {
    const errors: Record<string, string> = {};
    this.errors?.forEach((e) => {
      errors[e.field] = e.message;
    });
    return errors;
  }

  /**
   * 获取所有字段错误，返回数组格式
   */
  getFieldErrorsArray(): FieldError[] {
    return this.errors || [];
  }
}

// ==================== Axios 实例配置 ====================

/**
 * 验证字符串是否符合 HTTP 请求头编码规范
 * HTTP/1.1 只允许可见 ASCII 字符 (32-126)
 */
function isValidHeaderValue(value: string): boolean {
  return /^[\x20-\x7E]*$/.test(value);
}

/**
 * 创建 axios 实例
 */
const apiClient = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api/v1',
  timeout: 30000,
  headers: {
    'Content-Type': 'application/json',
  },
  // 正确序列化数组参数 (groupIds=[id1,id2] -> groupIds=id1&groupIds=id2)
  paramsSerializer: (params) => {
    const searchParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (Array.isArray(value)) {
        // 数组：重复参数名 (groupIds=id1&groupIds=id2)
        value.forEach(item => searchParams.append(key, String(item)));
      } else if (value !== undefined && value !== null) {
        // 普通值
        searchParams.append(key, String(value));
      }
    });
    return searchParams.toString();
  },
});

// ==================== 请求拦截器 ====================

apiClient.interceptors.request.use(
  (config) => {
    // 添加 Token
    const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }

    // 添加请求 ID（用于追踪和调试）
    config.headers['X-Request-ID'] = generateRequestId();

    // ⭐ 使用 Unix 时间戳（避免 ISO-8859-1 编码问题）
    // HTTP头只支持 ASCII 字符，Unix时间戳是纯数字，100%兼容
    config.headers['X-Request-Time'] = String(Date.now());

    // 添加区域 ID（用于多区域数据隔离）
    // 从 localStorage 获取当前选择的区域
    if (typeof window !== 'undefined') {
      const currentRegion = localStorage.getItem('ffoa_current_region') || 'CN';
      config.headers['X-Region-Id'] = currentRegion;

      // 添加当前组织 ID（issue #160）：让后端 JwtStrategy.validate 切出当前
      // 组织的权限切片，避免 v2.2 移除 region 兜底时组织级权限丢失。
      // STORAGE_KEY 与 OrganizationContext.tsx 一致；缺失则不传，后端会退回
      // 当前 v2.1 行为（region 兜底）。
      const currentOrgId = localStorage.getItem('selected_organization_id');
      if (currentOrgId) {
        config.headers['X-Organization-Id'] = currentOrgId;
      }
    }

    // 调试：打印请求 URL 和参数
    if (config.url?.includes('/parts')) {
      console.log('[API Interceptor] Request:', {
        url: config.url,
        baseURL: config.baseURL,
        params: config.params,
        method: config.method,
      });
    }

    // ⭐ 防御性编程：自动处理非ASCII字符的请求头
    // 遍历所有请求头，如果发现非ASCII字符，自动进行Base64编码
    Object.keys(config.headers).forEach((key) => {
      const value = config.headers[key];
      if (typeof value === 'string' && !isValidHeaderValue(value)) {
        // 开发环境下输出警告（生产环境保持静默，不影响性能）
        if (process.env.NODE_ENV === 'development') {
          console.warn(
            `[API] ⚠️ 请求头 "${key}" 包含非ASCII字符，已自动Base64编码`,
            { 
              originalValue: value, 
              length: value.length,
              encodedValue: btoa(encodeURIComponent(value))
            }
          );
        }
        
        // ✅ 自动编码为 Base64，确保100%兼容HTTP规范
        // 使用 encodeURIComponent 确保完整的 UTF-8 支持
        // 注意：不添加 -Encoding 标记头，避免 CORS 配置复杂化
        config.headers[key] = btoa(encodeURIComponent(value));
      }
    });

    return config;
  },
  (error) => {
    return Promise.reject(error);
  },
);

// ==================== Refresh Token 自动续期 ====================
// 规则 §2.2：access token 30min；遇 401 用 refresh token 自动换新并重放原请求

const REFRESH_TOKEN_KEY = 'refresh_token';

let refreshPromise: Promise<string> | null = null;

async function performRefresh(): Promise<string> {
  const refreshToken = localStorage.getItem(REFRESH_TOKEN_KEY);
  if (!refreshToken) throw new Error('No refresh token');

  const baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api/v1';
  const resp = await axios.post(
    `${baseURL}/auth/refresh`,
    { refreshToken },
    { headers: { 'Content-Type': 'application/json' } },
  );
  const data = resp.data?.data ?? resp.data;
  const { accessToken, refreshToken: newRefresh } = data;
  if (!accessToken) throw new Error('Refresh response missing accessToken');

  localStorage.setItem('token', accessToken);
  if (newRefresh) localStorage.setItem(REFRESH_TOKEN_KEY, newRefresh);
  return accessToken;
}

function clearAuthAndRedirect() {
  if (typeof window === 'undefined') return;
  localStorage.removeItem('token');
  localStorage.removeItem(REFRESH_TOKEN_KEY);
  const path = window.location.pathname;
  const isPublicAttendancePath =
    path.startsWith('/siteattendance/c/') ||
    path.startsWith('/siteattendance/shared/') ||
    path.startsWith('/siteattendance/display/');
  if (!isPublicAttendancePath && path !== '/login') {
    window.location.href = buildLoginRedirectUrl(getCurrentRelativePath());
  }
}

// ==================== 响应拦截器 ====================

apiClient.interceptors.response.use(
  (response: AxiosResponse<ApiResponse>) => {
    // 二进制响应（Blob / ArrayBuffer）不走统一 { data, success } 解包，直接返回原始 body
    // 否则 URL.createObjectURL(undefined) 会在文件下载场景报 "Overload resolution failed"
    const rt = response.config.responseType;
    if (rt === 'blob' || rt === 'arraybuffer' || rt === 'stream') {
      return response.data as any;
    }

    // 自动从 /auth/login / /auth/dev-email-login / /auth/refresh 响应里抓取 refreshToken
    // 减少调用方需要主动处理的负担
    const url = response.config.url || '';
    const isAuthEndpoint =
      url.includes('/auth/login') ||
      url.includes('/auth/dev-email-login') ||
      url.includes('/auth/refresh');
    if (isAuthEndpoint && typeof window !== 'undefined') {
      const data = response.data?.data;
      if (data?.refreshToken) {
        localStorage.setItem(REFRESH_TOKEN_KEY, data.refreshToken);
      }
    }

    // 成功响应，直接返回 data 字段
    return response.data.data;
  },
  async (error: AxiosError<ApiErrorResponse>) => {
    // 错误处理
    if (error.response) {
      const apiError = error.response.data;
      const errorInfo = apiError?.error;

      // 开发环境：打印详细的 API 错误信息
      if (process.env.NODE_ENV === 'development') {
        console.group('🔴 API Error');
        console.log('Status:', error.response.status);
        console.log('URL:', error.config?.url);
        console.log('Method:', error.config?.method?.toUpperCase());
        console.log('Error Code:', errorInfo?.code);
        console.log('Message:', errorInfo?.message);
        console.log('Details:', errorInfo?.details);
        console.log('Raw Response:', apiError);
        console.groupEnd();
      }

      // 401 - access token 过期或无效；先尝试用 refresh token 续期，失败再跳登录
      if (error.response.status === 401 && typeof window !== 'undefined') {
        const originalRequest = error.config as AxiosRequestConfig & { _retried?: boolean };
        const url = originalRequest?.url || '';
        const isAuthEndpoint =
          url.includes('/auth/login') ||
          url.includes('/auth/refresh') ||
          url.includes('/auth/dev-email-login');

        // 不对 auth 自身端点做续期（避免无限循环）；不对已重试过的请求再次重试
        if (!isAuthEndpoint && !originalRequest?._retried) {
          try {
            // 并发 401 共享同一个 refresh in-flight，避免重复续期
            const newToken = await (refreshPromise ??= performRefresh().finally(() => {
              refreshPromise = null;
            }));
            // 重放原请求
            originalRequest._retried = true;
            originalRequest.headers = {
              ...(originalRequest.headers || {}),
              Authorization: `Bearer ${newToken}`,
            };
            return apiClient(originalRequest);
          } catch {
            clearAuthAndRedirect();
          }
        } else {
          clearAuthAndRedirect();
        }
      }

      // 403 - 无权限
      // 错误消息将由 error-handler.ts 根据语言显示

      // 400 - 「organizationId required」专项兜底提示：
      // 用户没有组织归属 / 切换到无效 org 时所有 API 全部 400，业务层各自 setError
      // 散落难发现。这里集中弹一次明确 toast。详见
      // .learnings/ERRORS/ERR-20260518-004-reset-db-missing-organization-seed.md
      if (
        error.response.status === 400 &&
        typeof window !== 'undefined' &&
        /organizationId required/i.test(apiError?.error?.message ?? '')
      ) {
        const t = getTranslations(getCurrentLocale()).common;
        toast.error(t.noOrganizationToastTitle, {
          description: t.noOrganizationToastDescription,
          id: 'no-org-toast', // 同一 id 避免连发 N 个 toast
          duration: 6000,
        });
      }

      // 500 - 服务器错误
      // 错误消息将由 error-handler.ts 根据语言显示

      // 返回格式化的错误（业务层会进一步处理）
      // 确保 apiError 有正确的结构
      const normalizedError: ApiErrorResponse = {
        success: false,
        error: errorInfo || {
          code: `HTTP_${error.response.status}`,
          message: error.message || 'Request failed',
        },
        timestamp: apiError?.timestamp || new Date().toISOString(),
        path: apiError?.path || error.config?.url || '',
        method: apiError?.method || error.config?.method?.toUpperCase() || 'GET',
        statusCode: error.response.status,
      };
      return Promise.reject(new ApiClientError(normalizedError));
    }

    // 网络错误
    if (error.request) {
      const networkError: ApiErrorResponse = {
        success: false,
        error: {
          code: 'NETWORK_ERROR',
          message: 'Network connection failed',
        },
        timestamp: new Date().toISOString(),
        path: error.config?.url || '',
        method: error.config?.method?.toUpperCase() || 'GET',
        statusCode: 0,
      };
      return Promise.reject(new ApiClientError(networkError));
    }

    // 其他错误
    const unknownError: ApiErrorResponse = {
      success: false,
      error: {
        code: 'UNKNOWN_ERROR',
        message: error.message || 'Unknown error',
      },
      timestamp: new Date().toISOString(),
      path: error.config?.url || '',
      method: error.config?.method?.toUpperCase() || 'GET',
      statusCode: 0,
    };
    return Promise.reject(new ApiClientError(unknownError));
  },
);

// ==================== 辅助函数 ====================

/**
 * 生成请求 ID
 */
function generateRequestId(): string {
  return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}

/**
 * 显示通知
 */
function showNotification(
  type: 'success' | 'error' | 'warning' | 'info',
  message: string,
) {
  // 集成你的 toast 组件
  // 这里只是简单的 console，实际应该使用 toast 组件
  if (typeof window !== 'undefined') {
    console.log(`[${type.toUpperCase()}]`, message);
    // 示例：如果你使用 react-hot-toast
    // toast[type](message);
  }
}

// ==================== 类型安全的请求方法 ====================

/**
 * GET 请求
 */
export async function get<T = any>(
  url: string,
  config?: AxiosRequestConfig,
): Promise<T> {
  return apiClient.get<any, T>(url, config);
}

/**
 * POST 请求
 */
export async function post<T = any>(
  url: string,
  data?: any,
  config?: AxiosRequestConfig,
): Promise<T> {
  return apiClient.post<any, T>(url, data, config);
}

/**
 * PUT 请求
 */
export async function put<T = any>(
  url: string,
  data?: any,
  config?: AxiosRequestConfig,
): Promise<T> {
  return apiClient.put<any, T>(url, data, config);
}

/**
 * PATCH 请求
 */
export async function patch<T = any>(
  url: string,
  data?: any,
  config?: AxiosRequestConfig,
): Promise<T> {
  return apiClient.patch<any, T>(url, data, config);
}

/**
 * DELETE 请求
 */
export async function del<T = any>(
  url: string,
  config?: AxiosRequestConfig,
): Promise<T> {
  return apiClient.delete<any, T>(url, config);
}

// 导出 axios 实例（用于特殊情况）
export default apiClient;

// 导出类型（方便其他模块使用）
export type { AxiosRequestConfig };
