import axios from 'axios';
import type { AxiosInstance } from 'axios';
import type {
  LoginRequest,
  LoginResponse,
  RefreshResponse,
  MicrosoftLoginResponse,
  Job,
  JobCreateRequest,
  JobListResponse,
  JobDownloadsResponse,
  VttContentResponse,
  VttUpdateRequest,
  AssetValidationResponse,
  BulkDeleteRequest,
  BulkDeleteResponse,
  JobDeleteResponse,
  User,
  UserListResponse,
  CreateUserRequest,
  UpdateUserRequest,
  ResetPasswordResponse,
  AdminStatsResponse,
  VoicesResponse,
  LanguagesResponse,
  TTSPreferences,
  TTSOptionsResponse,
  TTSStylePreset,
} from '../types/api';

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000';

class ApiClient {
  private client: AxiosInstance;
  private accessToken: string | null = null;

  constructor() {
    this.client = axios.create({
      baseURL: `${API_BASE_URL}/api/v1`,
      withCredentials: true,
      timeout: 30000,
    });

    this.setupInterceptors();
  }

  private setupInterceptors() {
    // Request interceptor to add auth token
    this.client.interceptors.request.use(
      (config) => {
        if (this.accessToken) {
          config.headers.Authorization = `Bearer ${this.accessToken}`;
        }
        return config;
      },
      (error) => Promise.reject(error)
    );

    // Response interceptor to handle token refresh
    this.client.interceptors.response.use(
      (response) => response,
      async (error) => {
        const originalRequest = error.config;

        // Don't try to refresh if this is already the refresh endpoint
        if (error.response?.status === 401 && 
            !originalRequest._retry && 
            originalRequest.url !== '/auth/refresh') {
          originalRequest._retry = true;

          try {
            const refreshResponse = await this.client.post('/auth/refresh');
            this.accessToken = refreshResponse.data.access_token;
            
            // Retry original request with new token
            originalRequest.headers.Authorization = `Bearer ${this.accessToken}`;
            return this.client(originalRequest);
          } catch (refreshError) {
            // Refresh failed, clear token and update auth state
            this.accessToken = null;
            // Clear auth state in the store
            const { useAuthStore } = await import('./auth');
            useAuthStore.getState().logout();
            return Promise.reject(refreshError);
          }
        }

        return Promise.reject(error);
      }
    );
  }

  setAccessToken(token: string) {
    this.accessToken = token;
  }

  clearAccessToken() {
    this.accessToken = null;
  }

  getAccessToken(): string | null {
    return this.accessToken;
  }

  // Auth endpoints
  async login(credentials: LoginRequest): Promise<LoginResponse> {
    const response = await this.client.post('/auth/login', credentials);
    this.setAccessToken(response.data.access_token);
    return response.data;
  }

  async loginWithMicrosoft(idToken: string): Promise<MicrosoftLoginResponse> {
    const response = await this.client.post('/auth/microsoft', { id_token: idToken });
    this.setAccessToken(response.data.access_token);
    return response.data;
  }

  async refresh(): Promise<RefreshResponse> {
    const response = await this.client.post('/auth/refresh');
    this.setAccessToken(response.data.access_token);
    return response.data;
  }

  async logout(): Promise<void> {
    await this.client.post('/auth/logout');
    this.clearAccessToken();
  }

  // Job endpoints
  async getJobs(filters?: { status?: string; mine?: boolean; page?: number; size?: number }): Promise<JobListResponse> {
    const params = new URLSearchParams();
    if (filters?.status) params.append('status', filters.status);
    if (filters?.mine) params.append('mine', 'true');
    if (filters?.page) params.append('page', filters.page.toString());
    if (filters?.size) params.append('size', filters.size.toString());

    const response = await this.client.get(`/jobs?${params.toString()}`);
    return response.data;
  }

  async getJob(id: string): Promise<Job> {
    const response = await this.client.get(`/jobs/${id}`);
    return response.data;
  }

  async createJob(data: JobCreateRequest, file: File, onUploadProgress?: (progressEvent: { loaded: number; total: number }) => void): Promise<Job> {
    const formData = new FormData();
    formData.append('title', data.title);
    formData.append('source_is_english', String(data.source_is_english));
    if (data.language_hint) {
      formData.append('language_hint', data.language_hint);
    }
    formData.append('requested_outputs', JSON.stringify(data.requested_outputs));
    formData.append('file', file);

    const response = await this.client.post('/jobs', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      timeout: 0, // No timeout for video uploads (can be large files)
      onUploadProgress: onUploadProgress ? (progressEvent) => {
        if (progressEvent.total) {
          onUploadProgress({
            loaded: progressEvent.loaded,
            total: progressEvent.total
          });
        }
      } : undefined,
    });
    return response.data;
  }

  async updateJob(id: string, data: Partial<Job>): Promise<Job> {
    const response = await this.client.patch(`/jobs/${id}`, data);
    return response.data;
  }

  async approveEnglish(id: string, notes?: string): Promise<Job> {
    // Legacy method - calls approve_source for backwards compatibility
    return this.approveSource(id, notes);
  }

  async approveSource(id: string, notes?: string, tts_preferences?: TTSPreferences): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/approve_source`, {
      notes,
      tts_preferences
    });
    return response.data;
  }

  async rejectJob(id: string, notes: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/reject`, { notes });
    return response.data;
  }

  async completeJob(id: string, notes?: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/complete`, { notes });
    return response.data;
  }

  async rejectFinalReview(id: string, notes: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/reject_final`, { notes });
    return response.data;
  }

  async getJobDownloads(id: string): Promise<JobDownloadsResponse> {
    const response = await this.client.get(`/jobs/${id}/downloads`);
    return response.data;
  }

  async getJobVttContent(id: string, language?: string): Promise<VttContentResponse> {
    const params = language ? `?language=${language}` : '';
    const response = await this.client.get(`/jobs/${id}/vtt${params}`);
    return response.data;
  }

  async updateJobVttContent(id: string, data: VttUpdateRequest): Promise<Job> {
    const response = await this.client.patch(`/jobs/${id}/vtt`, data);
    return response.data;
  }

  async adjustVttTiming(id: string, data: {
    offset_seconds: number;
    language?: string;
    adjust_captions?: boolean;
    adjust_audio_description?: boolean;
  }): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/vtt/adjust-timing`, data);
    return response.data;
  }

  async validateJobAssets(id: string): Promise<AssetValidationResponse> {
    const response = await this.client.get(`/jobs/${id}/validate`);
    return response.data;
  }

  async deleteJob(id: string): Promise<JobDeleteResponse> {
    const response = await this.client.delete(`/jobs/${id}`);
    return response.data;
  }

  async bulkDeleteJobs(data: BulkDeleteRequest): Promise<BulkDeleteResponse> {
    const response = await this.client.delete('/jobs/bulk', { data });
    return response.data;
  }

  async reprocessJob(id: string): Promise<{ message: string }> {
    const response = await this.client.post(`/admin/maintenance/reprocess-job/${id}`);
    return response.data;
  }

  // User Management endpoints
  async listUsers(filters?: {
    page?: number;
    size?: number;
    role?: string;
    active_only?: boolean;
  }): Promise<UserListResponse> {
    const params = new URLSearchParams();
    if (filters?.page) params.append('page', filters.page.toString());
    if (filters?.size) params.append('size', filters.size.toString());
    if (filters?.role) params.append('role', filters.role);
    if (filters?.active_only !== undefined) params.append('active_only', filters.active_only.toString());

    const response = await this.client.get(`/admin/users?${params.toString()}`);
    return response.data;
  }

  async getUser(userId: string): Promise<User> {
    const response = await this.client.get(`/admin/users/${userId}`);
    return response.data;
  }

  async createUser(data: CreateUserRequest): Promise<User> {
    const response = await this.client.post('/admin/users', data);
    return response.data;
  }

  async updateUser(userId: string, data: UpdateUserRequest): Promise<User> {
    const response = await this.client.patch(`/admin/users/${userId}`, data);
    return response.data;
  }

  async deactivateUser(userId: string): Promise<{ message: string }> {
    const response = await this.client.delete(`/admin/users/${userId}`);
    return response.data;
  }

  async resetUserPassword(userId: string): Promise<ResetPasswordResponse> {
    const response = await this.client.post(`/admin/users/${userId}/password/reset`);
    return response.data;
  }

  async getAdminStats(): Promise<AdminStatsResponse> {
    const response = await this.client.get('/admin/stats');
    return response.data;
  }

  // TTS endpoints
  async getVoices(): Promise<VoicesResponse> {
    const response = await this.client.get('/tts/voices');
    return response.data;
  }

  async getLanguages(): Promise<LanguagesResponse> {
    const response = await this.client.get('/tts/languages');
    return response.data;
  }

  async getTTSOptions(): Promise<TTSOptionsResponse> {
    const response = await this.client.get('/tts/options');
    return response.data;
  }

  async previewVoice(
    voiceName: string,
    language: string,
    model?: string,
    speed?: number,
    stylePreset?: TTSStylePreset,
    customStylePrompt?: string
  ): Promise<Blob> {
    const response = await this.client.post(
      '/tts/preview',
      {
        voice_name: voiceName,
        language,
        model: model || 'flash',
        speed: speed || 1.0,
        style_preset: stylePreset || 'neutral',
        custom_style_prompt: customStylePrompt
      },
      { responseType: 'blob' }
    );
    return response.data;
  }
}

export const apiClient = new ApiClient();
export const api = apiClient;