// src/client/shared/api.ts
// API client for backend communication with strict typing

import axios, { AxiosError, type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios';
import { useUserStore } from '../entities/user';
import { io, Socket } from 'socket.io-client';

const SOCKET_URL = import.meta.env.VITE_SOCKET_URL || 'http://localhost:3000'; // URL для WebSocket соединения

export const socket: Socket = io(SOCKET_URL, {
  withCredentials: true,
  transports: ['websocket'],
  autoConnect: false,
});

// Лог для дебага
socket.on('connect', () => console.log('[Socket] Connected:', socket.id));
socket.on('disconnect', (reason) => console.log('[Socket] Disconnected:', reason));
socket.on('connect_error', (error) => console.error('[Socket] Connection error:', error));

// Логирование всех входящих событий сокета
socket.onAny((event, ...args) => {
  console.log(`[Frontend Socket Raw] Received: ${event}`, args);
});

// Функция для явного подключения сокета
export function connectSocket() {
  if (!socket.connected) {
    console.log('[Socket] Connecting to socket...');
    socket.connect();
  } else {
    console.log('[Socket] Already connected:', socket.id);
  }
}

// Функция для отключения сокета
export function disconnectSocket() {
  if (socket.connected) {
    socket.disconnect();
  }
}

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

// Custom Error Class
export class ApiError extends Error {
  public code: string;
  public details?: any;

  constructor(message: string, code: string = 'UNKNOWN_ERROR', details?: any) {
    super(message);
    this.name = 'ApiError';
    this.code = code;
    this.details = details;
  }
}

// Standard API response wrapper
export interface ApiResponse<T> {
  success: boolean;
  data: T;
}

// API error response
export interface ApiErrorResponse {
  success: false;
  error: {
    message: string;
    code: string;
    details?: unknown;
  };
}

// Create axios instance
const axiosInstance: AxiosInstance = axios.create({
  baseURL: API_BASE_URL,
  withCredentials: true, // Send cookies with requests
  headers: {
    'Content-Type': 'application/json',
  },
});

// Interceptor to handle standard response wrapper
axiosInstance.interceptors.response.use(
  (response: AxiosResponse<ApiResponse<any>>) => {
    const data = response.data;
    
    // Extract data from standard response wrapper
    if (data && data.success) {
      return data.data;
    }
    
    // If response has error structure, throw ApiError
    if (data && !data.success && 'error' in data) {
      const error = (data as any).error;
      throw new ApiError(error.message, error.code, error.details);
    }
    
    // Return data as is if no standard wrapper
    return data;
  },
  (error: AxiosError<ApiErrorResponse>) => {
    // Handle Axios errors
    if (error.response) {
      const data = error.response.data;
      
      // Check if server returned our standard error structure
      if (data && data.error && data.error.message) {
        // Special handling for disabled account (fired employee)
        if (error.response.status === 403 && data.error.code === 'ACCOUNT_DISABLED') {
          // Clear local user state
          const userStore = useUserStore();
          userStore.clearUser();
          
          // Force redirect to login page with reason
          window.location.href = '/login?reason=fired';
          // Return a promise that never resolves to prevent further processing
          return new Promise(() => {});
        }
        
        // Special handling for expired session (401)
        if (error.response.status === 401 && !window.location.pathname.includes('/login')) {
          // Clear local user state
          const userStore = useUserStore();
          userStore.clearUser();

          // Force redirect to login page with reason
          window.location.href = '/login?reason=session_expired';
          // Return a promise that never resolves to prevent further processing
          return new Promise(() => {});
        }
        
        throw new ApiError(data.error.message, data.error.code, data.error.details);
      }
      
      // Fallback based on status
      const fallbackMessage = error.response.status === 401
        ? 'Неверные учётные данные'
        : error.response.status === 403
        ? 'Доступ запрещён'
        : error.response.statusText || 'Неизвестная ошибка сервера';
      
      throw new ApiError(fallbackMessage, `HTTP_${error.response.status}`);
    }
    
    // Network errors
    throw new ApiError('Ошибка сети или сервер недоступен', 'NETWORK_ERROR');
  }
);

// Typed API methods
export const api = {
  get: <ResponseData>(endpoint: string, config?: AxiosRequestConfig) =>
    axiosInstance.get<ApiResponse<ResponseData>, ResponseData>(endpoint, config),
  
  post: <RequestData, ResponseData>(
    endpoint: string,
    body: RequestData,
    config?: AxiosRequestConfig
  ) =>
    axiosInstance.post<ApiResponse<ResponseData>, ResponseData>(endpoint, body, config),
  
  put: <RequestData, ResponseData>(
    endpoint: string,
    body: RequestData,
    config?: AxiosRequestConfig
  ) =>
    axiosInstance.put<ApiResponse<ResponseData>, ResponseData>(endpoint, body, config),
  
  patch: <RequestData, ResponseData>(
    endpoint: string,
    body: RequestData,
    config?: AxiosRequestConfig
  ) =>
    axiosInstance.patch<ApiResponse<ResponseData>, ResponseData>(endpoint, body, config),
  
  delete: <ResponseData>(endpoint: string, config?: AxiosRequestConfig) =>
    axiosInstance.delete<ApiResponse<ResponseData>, ResponseData>(endpoint, config),
};

// Rooms API
export interface Room {
  id: string;
  type: 'апарт' | 'номер';
  hasHood: boolean;
  beds: number;
  armchair: boolean;
  airCond: boolean;
  isRepairing: boolean;
  repairReason: string | null;
  comment: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface CreateRoomInput {
  id: string;
  type: 'апарт' | 'номер';
  hasHood?: boolean;
  beds?: number;
  armchair?: boolean;
  airCond?: boolean;
  isRepairing?: boolean;
  repairReason?: string;
  comment?: string;
}

export interface UpdateRoomInput {
  id?: string;
  type?: 'апарт' | 'номер';
  hasHood?: boolean;
  beds?: number;
  armchair?: boolean;
  airCond?: boolean;
  isRepairing?: boolean;
  repairReason?: string;
  comment?: string;
}

export const roomsApi = {
  getAll: () =>
    api.get<Room[]>('/rooms'),
  
  getById: (id: string) =>
    api.get<Room>(`/rooms/${id}`),
  
  create: (data: CreateRoomInput) =>
    api.post<CreateRoomInput, Room>('/rooms', data),
  
  update: (id: string, data: UpdateRoomInput) =>
    api.put<UpdateRoomInput, Room>(`/rooms/${id}`, data),
  
  delete: (id: string) =>
    api.delete<{ success: boolean; message: string }>(`/rooms/${id}`),
};
