import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { API_BASE_URL } from './constants';
import type {
  AuthResponse,
  User,
  UserProfile,
  Channel,
  Movie,
  Series,
  Episode,
  Category,
  Favorite,
  HistoryItem,
  SearchResult,
  AdminStats,
  ApiResponse,
  PaginatedResponse,
  CreateUserPayload,
  UpdateUserPayload,
  CreateChannelPayload,
  CreateMoviePayload,
  CreateSeriesPayload,
} from '@/types';

// Create axios instance
const api: AxiosInstance = axios.create({
  baseURL: API_BASE_URL,
  timeout: 15000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Request interceptor - attach JWT
api.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    if (typeof window !== 'undefined') {
      const token = localStorage.getItem('accessToken');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// Response interceptor - reject promise on error without forcing automatic logouts
api.interceptors.response.use(
  (response: AxiosResponse) => response,
  (error: AxiosError) => {
    // We do not force automatic logout on network failures or 401 errors.
    // This prevents temporary IPTV server overloads, connection limits, or timeouts from wiping the user's session.
    return Promise.reject(error);
  }
);

// ============ Auth API ============
export const authApi = {
  login: async (email: string, password: string, dns?: string): Promise<AuthResponse> => {
    const { data } = await api.post<ApiResponse<AuthResponse>>('/auth/login', { email, password, dns });
    return data.data;
  },

  register: async (payload: CreateUserPayload): Promise<AuthResponse> => {
    const { data } = await api.post<ApiResponse<AuthResponse>>('/auth/register', payload);
    return data.data;
  },

  logout: async (): Promise<void> => {
    try {
      await api.post('/auth/logout');
    } finally {
      localStorage.removeItem('accessToken');
      localStorage.removeItem('refreshToken');
      localStorage.removeItem('user');
    }
  },

  refreshToken: async (): Promise<AuthResponse> => {
    const refreshToken = localStorage.getItem('refreshToken');
    const { data } = await api.post<ApiResponse<AuthResponse>>('/auth/refresh', { refreshToken });
    return data.data;
  },

  getProfile: async (): Promise<UserProfile> => {
    const { data } = await api.get<ApiResponse<UserProfile>>('/auth/profile');
    return data.data;
  },

  changePassword: async (currentPassword: string, newPassword: string): Promise<void> => {
    await api.put('/auth/change-password', { currentPassword, newPassword });
  },
};

// ============ Channels API ============
export const channelsApi = {
  getAll: async (categoryId?: string): Promise<Channel[]> => {
    const params = categoryId && categoryId !== 'all' ? { category: categoryId } : {};
    const { data } = await api.get<ApiResponse<Channel[]>>('/channels', { params });
    return data.data;
  },

  getById: async (id: string): Promise<Channel> => {
    const { data } = await api.get<ApiResponse<Channel>>(`/channels/${id}`);
    return data.data;
  },

  getCategories: async (): Promise<Category[]> => {
    const { data } = await api.get<ApiResponse<Category[]>>('/channels/categories');
    return data.data;
  },

  getEpg: async (streamId: string): Promise<any[]> => {
    const { data } = await api.get<ApiResponse<any[]>>('/channels/epg', { params: { streamId } });
    return data.data;
  },
};

// ============ Movies API ============
export const moviesApi = {
  getAll: async (page = 1, limit = 20, genre?: string): Promise<PaginatedResponse<Movie>> => {
    const params: Record<string, unknown> = { page, limit };
    if (genre && genre !== 'all') params.genre = genre;
    const { data } = await api.get<PaginatedResponse<Movie>>('/movies', { params });
    return data;
  },

  getById: async (id: string): Promise<Movie> => {
    const { data } = await api.get<ApiResponse<Movie>>(`/movies/${id}`);
    return data.data;
  },

  getPopular: async (limit = 10): Promise<Movie[]> => {
    const { data } = await api.get<ApiResponse<Movie[]>>('/movies/popular', { params: { limit } });
    return data.data;
  },

  getRecent: async (limit = 10): Promise<Movie[]> => {
    const { data } = await api.get<ApiResponse<Movie[]>>('/movies/recent', { params: { limit } });
    return data.data;
  },

  getCategories: async (): Promise<Category[]> => {
    const { data } = await api.get<ApiResponse<Category[]>>('/movies/categories');
    return data.data;
  },
};

// ============ Series API ============
export const seriesApi = {
  getAll: async (page = 1, limit = 20, genre?: string): Promise<PaginatedResponse<Series>> => {
    const params: Record<string, unknown> = { page, limit };
    if (genre && genre !== 'all') params.genre = genre;
    const { data } = await api.get<PaginatedResponse<Series>>('/series', { params });
    return data;
  },

  getById: async (id: string): Promise<Series> => {
    const { data } = await api.get<ApiResponse<Series>>(`/series/${id}`);
    return data.data;
  },

  getPopular: async (limit = 10): Promise<Series[]> => {
    const { data } = await api.get<ApiResponse<Series[]>>('/series/popular', { params: { limit } });
    return data.data;
  },

  getEpisodes: async (seriesId: string, seasonNumber: number): Promise<Episode[]> => {
    const { data } = await api.get<ApiResponse<Episode[]>>(`/series/${seriesId}/seasons/${seasonNumber}/episodes`);
    return data.data;
  },

  getCategories: async (): Promise<Category[]> => {
    const { data } = await api.get<ApiResponse<Category[]>>('/series/categories');
    return data.data;
  },
};

// ============ Search API ============
export const searchApi = {
  search: async (query: string, filter: string = 'all'): Promise<SearchResult> => {
    const { data } = await api.get<ApiResponse<SearchResult>>('/search', {
      params: { q: query, filter },
    });
    return data.data;
  },
};

// ============ Favorites API ============
export const favoritesApi = {
  getAll: async (): Promise<Favorite[]> => {
    const { data } = await api.get<ApiResponse<Favorite[]>>('/favorites');
    return data.data;
  },

  add: async (type: string, contentId: string): Promise<Favorite> => {
    const { data } = await api.post<ApiResponse<Favorite>>('/favorites', { type, contentId });
    return data.data;
  },

  remove: async (id: string): Promise<void> => {
    await api.delete(`/favorites/${id}`);
  },

  toggle: async (type: string, contentId: string): Promise<{ isFavorite: boolean }> => {
    const { data } = await api.post<ApiResponse<{ isFavorite: boolean }>>('/favorites/toggle', {
      type,
      contentId,
    });
    return data.data;
  },
};

// ============ History API ============
export const historyApi = {
  getAll: async (limit = 20): Promise<HistoryItem[]> => {
    const { data } = await api.get<ApiResponse<HistoryItem[]>>('/history', { params: { limit } });
    return data.data;
  },

  addOrUpdate: async (
    type: string,
    contentId: string,
    progress: number,
    duration: number
  ): Promise<void> => {
    await api.post('/history', { type, contentId, progress, duration });
  },

  remove: async (id: string): Promise<void> => {
    await api.delete(`/history/${id}`);
  },
};

// ============ Admin API ============
export const adminApi = {
  getStats: async (): Promise<AdminStats> => {
    const { data } = await api.get<ApiResponse<AdminStats>>('/admin/stats');
    return data.data;
  },

  // Users
  getUsers: async (page = 1, limit = 20, search?: string): Promise<PaginatedResponse<User>> => {
    const params: Record<string, unknown> = { page, limit };
    if (search) params.search = search;
    const { data } = await api.get<PaginatedResponse<User>>('/admin/users', { params });
    return data;
  },

  createUser: async (payload: CreateUserPayload): Promise<User> => {
    const { data } = await api.post<ApiResponse<User>>('/admin/users', payload);
    return data.data;
  },

  updateUser: async (id: string, payload: UpdateUserPayload): Promise<User> => {
    const { data } = await api.put<ApiResponse<User>>(`/admin/users/${id}`, payload);
    return data.data;
  },

  deleteUser: async (id: string): Promise<void> => {
    await api.delete(`/admin/users/${id}`);
  },

  resetPassword: async (id: string, newPassword: string): Promise<void> => {
    await api.post(`/admin/users/${id}/reset-password`, { newPassword });
  },

  // Channels
  getChannels: async (page = 1, limit = 50): Promise<PaginatedResponse<Channel>> => {
    const { data } = await api.get<PaginatedResponse<Channel>>('/admin/channels', {
      params: { page, limit },
    });
    return data;
  },

  createChannel: async (payload: CreateChannelPayload): Promise<Channel> => {
    const { data } = await api.post<ApiResponse<Channel>>('/admin/channels', payload);
    return data.data;
  },

  updateChannel: async (id: string, payload: Partial<CreateChannelPayload>): Promise<Channel> => {
    const { data } = await api.put<ApiResponse<Channel>>(`/admin/channels/${id}`, payload);
    return data.data;
  },

  deleteChannel: async (id: string): Promise<void> => {
    await api.delete(`/admin/channels/${id}`);
  },

  // Movies
  createMovie: async (payload: CreateMoviePayload): Promise<Movie> => {
    const { data } = await api.post<ApiResponse<Movie>>('/admin/movies', payload);
    return data.data;
  },

  updateMovie: async (id: string, payload: Partial<CreateMoviePayload>): Promise<Movie> => {
    const { data } = await api.put<ApiResponse<Movie>>(`/admin/movies/${id}`, payload);
    return data.data;
  },

  deleteMovie: async (id: string): Promise<void> => {
    await api.delete(`/admin/movies/${id}`);
  },

  // Series
  createSeries: async (payload: CreateSeriesPayload): Promise<Series> => {
    const { data } = await api.post<ApiResponse<Series>>('/admin/series', payload);
    return data.data;
  },

  updateSeries: async (id: string, payload: Partial<CreateSeriesPayload>): Promise<Series> => {
    const { data } = await api.put<ApiResponse<Series>>(`/admin/series/${id}`, payload);
    return data.data;
  },

  deleteSeries: async (id: string): Promise<void> => {
    await api.delete(`/admin/series/${id}`);
  },
};

export default api;
