import { API_URL } from '../config';
import { ISettings, IContent } from '../types';
import {
  ApiError,
  ApiResponse,
  AnalyticsPayload,
  OrderRequestPayload,
} from '../types/api';

async function handleResponse<T>(response: Response): Promise<T> {
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  const data = (await response.json()) as ApiResponse<T>;
  if (data.err) {
    throw new Error(data.err.message);
  }
  return data.res;
}

const Api = {
  currentApiUrl: API_URL,

  initialize(config?: { debug?: { apiUrl?: string } }) {
    this.currentApiUrl = config?.debug?.apiUrl || API_URL;
  },

  get apiUrl(): string {
    return this.currentApiUrl;
  },

  async getSettings(
    apiKey: string,
    widgetVersion: number,
    localization?: string,
  ): Promise<ISettings & { id: string }> {
    const url = new URL('/api/widget/settings', this.currentApiUrl);
    url.searchParams.append('apiKey', apiKey);
    url.searchParams.append('widgetVersion', widgetVersion.toString());
    if (localization) {
      url.searchParams.append('localization', localization);
    }

    const response = await fetch(url.href, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    });

    return handleResponse<ISettings & { id: string }>(response);
  },

  async getContent(
    token: string,
    widgetVersion: number,
    sources?: {
      productIds?: string[];
      collectionIds?: string[];
    },
    settings?: ISettings,
  ): Promise<IContent> {
    const url = new URL('/api/widget/content', this.currentApiUrl);
    url.searchParams.append('apiKey', token);
    url.searchParams.append('widgetVersion', widgetVersion.toString());

    if (settings) {
      url.searchParams.append('settings', JSON.stringify(settings));
    }

    if (sources?.productIds?.length) {
      url.searchParams.append('products', sources.productIds.join(','));
    }

    if (sources?.collectionIds?.length) {
      url.searchParams.append('collections', sources.collectionIds.join(','));
    }

    const response = await fetch(url.href, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    });

    return handleResponse<IContent>(response);
  },

  async trackAnalyticsBatch(payloads: AnalyticsPayload[]): Promise<void> {
    const url = new URL('/api/widget/analytics/batch', this.currentApiUrl);

    const response = await fetch(url.href, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ events: payloads }),
      keepalive: true,
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
  },

  async trackOrder(payload: OrderRequestPayload): Promise<void> {
    const url = new URL('/api/widget/analytics/order', this.currentApiUrl);

    const response = await fetch(url.href, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(payload),
      keepalive: true,
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
  },
};

export default Api;
