import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { HelpCenterConfig } from '../lib/types';

export class ApiService {
  private axiosInstance: AxiosInstance;
  private config: HelpCenterConfig;
  private tokenExpiryTime: number = 0;
  private currentToken: string | null = null;

  constructor(config: HelpCenterConfig) {
    this.config = config;
    this.axiosInstance = axios.create({
      baseURL: config.baseUrl,
      headers: {
        'Content-Type': 'application/json',
      },
    });

    this.setupInterceptors();
  }

  private setupInterceptors() {
    this.axiosInstance.interceptors.request.use(
      async (config) => {
        const token = await this.getValidToken();
        if (token && config.headers) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
      (error) => Promise.reject(error)
    );

    this.axiosInstance.interceptors.response.use(
      (response) => response,
      async (error) => {
        if (error.response?.status === 401) {
          // Token might be expired, try to refresh
          const token = await this.getValidToken(true);
          if (token && error.config) {
            error.config.headers.Authorization = `Bearer ${token}`;
            return this.axiosInstance.request(error.config);
          }
        }
        return Promise.reject(error);
      }
    );
  }

  private async getValidToken(forceRefresh = false): Promise<string> {
    const currentTime = Math.floor(Date.now() / 1000);

    if (forceRefresh || !this.currentToken || currentTime >= this.tokenExpiryTime) {
      try {
        const response = await this.config.getToken();
        if (!response || !response.token || !response.expiresIn) {
          throw new Error('Invalid token response');
        }

        this.currentToken = response.token;
        this.tokenExpiryTime = currentTime + response.expiresIn;
        return this.currentToken;
      } catch (error) {
        throw error;
      }
    }

    return this.currentToken;
  }

  async get<T>(endpoint: string, config?: AxiosRequestConfig): Promise<T> {
    try {
      const response = await this.axiosInstance.get<T>(endpoint, config);
      return response.data;
    } catch (error) {
      this.handleError(error);
      throw error;
    }
  }

  async post<T>(endpoint: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
    try {
      const response = await this.axiosInstance.post<T>(endpoint, data, config);
      return response.data;
    } catch (error) {
      this.handleError(error);
      throw error;
    }
  }

  async put<T>(endpoint: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
    try {
      const response = await this.axiosInstance.put<T>(endpoint, data, config);
      return response.data;
    } catch (error) {
      this.handleError(error);
      throw error;
    }
  }

  async delete<T>(endpoint: string, config?: AxiosRequestConfig): Promise<T> {
    try {
      const response = await this.axiosInstance.delete<T>(endpoint, config);
      return response.data;
    } catch (error) {
      this.handleError(error);
      throw error;
    }
  }

  private handleError(error: unknown) {
    if (this.config.onError) {
      this.config.onError(error instanceof Error ? error : new Error('Unknown error occurred'));
    }
  }
}
