import axios, { AxiosInstance, AxiosError } from 'axios';
import { CloverConfig, PaginatedResponse } from '../types/index.js';

export class CloverClient {
  private client: AxiosInstance;
  private merchantId: string;

  constructor(config: CloverConfig) {
    this.merchantId = config.merchantId;
    
    const baseURL = config.environment === 'production'
      ? 'https://api.clover.com'
      : 'https://sandbox.dev.clover.com';

    this.client = axios.create({
      baseURL,
      headers: {
        'Content-Type': 'application/json',
        ...(config.accessToken && { 'Authorization': `Bearer ${config.accessToken}` }),
      },
      params: {
        ...(config.apiKey && { access_token: config.apiKey }),
      },
    });

    // Response interceptor for error handling
    this.client.interceptors.response.use(
      (response) => response,
      (error: AxiosError) => {
        if (error.response) {
          throw new Error(`Clover API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
        } else if (error.request) {
          throw new Error('Clover API Error: No response received');
        } else {
          throw new Error(`Clover API Error: ${error.message}`);
        }
      }
    );
  }

  // Generic GET method with pagination support
  async get<T>(endpoint: string, params: Record<string, any> = {}): Promise<T> {
    const url = `/v3/merchants/${this.merchantId}${endpoint}`;
    const response = await this.client.get<T>(url, { params });
    return response.data;
  }

  // Generic POST method
  async post<T>(endpoint: string, data: any): Promise<T> {
    const url = `/v3/merchants/${this.merchantId}${endpoint}`;
    const response = await this.client.post<T>(url, data);
    return response.data;
  }

  // Generic PUT method
  async put<T>(endpoint: string, data: any): Promise<T> {
    const url = `/v3/merchants/${this.merchantId}${endpoint}`;
    const response = await this.client.put<T>(url, data);
    return response.data;
  }

  // Generic DELETE method
  async delete<T>(endpoint: string): Promise<T> {
    const url = `/v3/merchants/${this.merchantId}${endpoint}`;
    const response = await this.client.delete<T>(url);
    return response.data;
  }

  // Paginated fetch helper
  async fetchPaginated<T>(
    endpoint: string,
    params: Record<string, any> = {},
    limit?: number
  ): Promise<T[]> {
    const allItems: T[] = [];
    let offset = 0;
    const pageSize = 100;

    while (true) {
      const response = await this.get<PaginatedResponse<T>>(endpoint, {
        ...params,
        limit: pageSize,
        offset,
      });

      allItems.push(...response.elements);

      if (response.elements.length < pageSize || (limit && allItems.length >= limit)) {
        break;
      }

      offset += pageSize;

      if (limit && allItems.length >= limit) {
        return allItems.slice(0, limit);
      }
    }

    return allItems;
  }

  getMerchantId(): string {
    return this.merchantId;
  }
}
