// src/client/shared/api/api.client.ts
// API client with Zod Interceptor for automatic contract validation

import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios';
import { z } from 'zod';
import { ApiError, ContractError, type ApiResponse, type ApiErrorResponse } from './errors';

// Глобальная типизация для window.clearUser
declare global {
  interface Window {
    clearUser?: () => void;
  }
}

const API_BASE_URL = import.meta.env.VITE_API_URL || '/api';

/**
 * Конфигурация запроса с опциональной Zod-схемой для валидации ответа
 */
export interface RequestConfig<T = any> extends AxiosRequestConfig {
  /**
   * Zod-схема для валидации ответа от сервера
   * Если указана, интерсептор выполнит schema.parse(data)
   */
  schema?: z.ZodType<T>;
}

/**
 * Создает экземпляр Axios с настроенным интерсептором для валидации Zod
 */
export function createApiClient(): AxiosInstance {
  const instance = axios.create({
    baseURL: API_BASE_URL,
    withCredentials: true, // Отправляем cookies с запросами
    headers: {
      'Content-Type': 'application/json',
    },
  });

  // Request interceptor для отладки путей
  instance.interceptors.request.use(config => {
    // Полный URL с нормализацией слэшей
    const fullUrl = `${config.baseURL}${config.url}`.replace(/\/+/g, '/');
    console.warn(`[🚀 API SEND] ${config.method?.toUpperCase()} -> ${fullUrl}`);
    return config;
  });

  // Response interceptor для обработки стандартной обертки и валидации Zod
  instance.interceptors.response.use(
    (response: AxiosResponse) => {
      const data = response.data;
      const config = response.config as RequestConfig;
      
      // Извлекаем данные из стандартной обертки ответа
      let responseData: any;
      if (data && typeof data === 'object' && 'success' in data) {
        if (data.success && 'data' in data) {
          responseData = data.data;
        }
        
        // Если ответ имеет структуру ошибки, выбрасываем ApiError
        else if (!data.success && 'error' in data) {
          const error = data.error;
          throw new ApiError(error.message, error.code, error.details);
        } else {
          // Возвращаем данные как есть, если нет стандартной обертки
          return data;
        }
      } else {
        // Возвращаем данные как есть, если нет стандартной обертки
        return data;
      }
      
      // Если передана схема, валидируем ответ
      if (config?.schema) {
        // ВОТ ЭТОТ ЛОГ ПОКАЖЕТ, ЧТО ПРИШЛО ИЗ СЕТИ НА САМОМ ДЕЛЕ
        // Если тут данные есть, а после парсинга пропали — значит Zod сука
        console.log('[NETWORK_RAW] Raw data from server:', responseData);
        if (Array.isArray(responseData) && responseData.length > 0) {
          console.log('[NETWORK_RAW] First note lastMentionAt from server:', responseData[0]?.lastMentionAt);
        }

        const result = config.schema.safeParse(responseData);
        if (!result.success) {
          const validationErrors: Record<string, string> = {};
          result.error.issues.forEach(err => {
            const path = err.path.join('.');
            validationErrors[path] = err.message;
          });

          console.error('[API] Validation Error:', {
            url: config.url,
            method: config.method?.toUpperCase(),
            errors: result.error.issues,
            received: responseData,
          });

          // Extended logging for contract debugging
          console.warn('[CONTRACT MISS] Path:', result.error.issues[0].path, 'Expected:', result.error.issues[0].code);

          throw new ContractError(
            'Ответ сервера не соответствует контракту',
            validationErrors
          );
        }

        // Возвращаем валидированные данные
        return result.data;
      }
      
      // Возвращаем данные без валидации
      return responseData;
    },
    (error) => {
      // Обработка ошибок Axios
      if (error.response) {
        const data = error.response.data;
        
        // Проверяем, вернул ли сервер нашу стандартную структуру ошибки
        if (data && data.error && data.error.message) {
          // Специальная обработка для отключенного аккаунта (уволенный сотрудник)
          if (error.response.status === 403 && data.error.code === 'ACCOUNT_DISABLED') {
            // Очищаем пользователя через глобальный обработчик
            if (window.clearUser) {
              window.clearUser();
            }
            
            // Принудительный редирект на страницу входа с причиной
            window.location.href = '/login?reason=fired';
            // Возвращаем промис, который никогда не резолвится
            return new Promise(() => {});
          }
          
          // Специальная обработка для истекшей сессии (401)
          if (error.response.status === 401 && !window.location.pathname.includes('/login')) {
            // Очищаем пользователя через глобальный обработчик
            if (window.clearUser) {
              window.clearUser();
            }
            
            // Принудительный редирект на страницу входа с причиной
            window.location.href = '/login?reason=session_expired';
            // Возвращаем промис, который никогда не резолвится
            return new Promise(() => {});
          }
          
          throw new ApiError(data.error.message, data.error.code, data.error.details);
        }
        
        // Fallback на основе статуса
        const fallbackMessage = error.response.status === 401
          ? 'Неверные учётные данные'
          : error.response.status === 403
          ? 'Доступ запрещён'
          : error.response.statusText || 'Неизвестная ошибка сервера';
        
        throw new ApiError(fallbackMessage, `HTTP_${error.response.status}`);
      }
      
      // Сетевые ошибки
      throw new ApiError('Ошибка сети или сервер недоступен', 'NETWORK_ERROR');
    }
  );

  return instance;
}

/**
 * Экземпляр API клиента
 */
export const apiClient = createApiClient();

/**
 * Типизированные методы API с поддержкой Zod-валидации
 * Валидация выполняется автоматически в интерсепторе, если передана схема
 */
export const api = {
  /**
   * GET запрос с опциональной Zod-валидацией ответа
   */
  get: <ResponseData = any>(endpoint: string, config?: RequestConfig<ResponseData>) => {
    return apiClient.get<ApiResponse<ResponseData>, ResponseData>(endpoint, config);
  },
  
  /**
   * POST запрос с опциональной Zod-валидацией ответа
   */
  post: <RequestData = any, ResponseData = any>(
    endpoint: string,
    body: RequestData,
    config?: RequestConfig<ResponseData>
  ) => {
    return apiClient.post<ApiResponse<ResponseData>, ResponseData>(endpoint, body, config);
  },
  
  /**
   * PUT запрос с опциональной Zod-валидацией ответа
   */
  put: <RequestData = any, ResponseData = any>(
    endpoint: string,
    body: RequestData,
    config?: RequestConfig<ResponseData>
  ) => {
    return apiClient.put<ApiResponse<ResponseData>, ResponseData>(endpoint, body, config);
  },
  
  /**
   * PATCH запрос с опциональной Zod-валидацией ответа
   */
  patch: <RequestData = any, ResponseData = any>(
    endpoint: string,
    body: RequestData,
    config?: RequestConfig<ResponseData>
  ) => {
    return apiClient.patch<ApiResponse<ResponseData>, ResponseData>(endpoint, body, config);
  },
  
  /**
   * DELETE запрос с опциональной Zod-валидацией ответа
   */
  delete: <ResponseData = any>(endpoint: string, config?: RequestConfig<ResponseData>) => {
    return apiClient.delete<ApiResponse<ResponseData>, ResponseData>(endpoint, config);
  },
};
