import axios, {AxiosInstance} from 'axios';
import {
  AddonManifest,
  CatalogResponse,
  ContentType,
  MetaResponse,
  StreamResponse,
  SubtitleResponse,
} from './addonTypes';

const TIMEOUT_MS = 8000;

export class AddonClient {
  private manifest: AddonManifest;
  private baseUrl: string;
  private http: AxiosInstance;

  constructor(transportUrl: string, manifest: AddonManifest) {
    this.baseUrl = transportUrl.replace(/\/manifest\.json$/, '');
    this.manifest = manifest;
    this.http = axios.create({
      baseURL: this.baseUrl,
      timeout: TIMEOUT_MS,
    });
  }

  static async fromUrl(manifestUrl: string): Promise<AddonClient> {
    const response = await axios.get(manifestUrl, {timeout: TIMEOUT_MS});
    const manifest = response.data as AddonManifest;
    return new AddonClient(manifestUrl, manifest);
  }

  getManifest(): AddonManifest {
    return this.manifest;
  }

  supportsResource(resource: string, type: ContentType, id?: string): boolean {
    const res = this.manifest.resources.find(r =>
      typeof r === 'string' ? r === resource : r.name === resource,
    );
    if (!res) return false;

    if (typeof res === 'object') {
      if (res.types && !res.types.includes(type)) return false;
      if (id && res.idPrefixes) {
        if (!res.idPrefixes.some(p => id.startsWith(p))) return false;
      }
    }

    return true;
  }

  async getCatalog(
    type: ContentType,
    catalogId: string,
    extra?: Record<string, string>,
  ): Promise<CatalogResponse> {
    let path = `/catalog/${type}/${catalogId}`;
    if (extra && Object.keys(extra).length > 0) {
      const extraStr = Object.entries(extra)
        .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
        .join('&');
      path += `/${extraStr}`;
    }
    const response = await this.http.get(`${path}.json`);
    return response.data;
  }

  async getMeta(type: ContentType, id: string): Promise<MetaResponse> {
    const response = await this.http.get(`/meta/${type}/${id}.json`);
    return response.data;
  }

  async getStreams(type: ContentType, id: string): Promise<StreamResponse> {
    const response = await this.http.get(`/stream/${type}/${id}.json`);
    return response.data;
  }

  async getSubtitles(
    type: ContentType,
    id: string,
    extra?: Record<string, string>,
  ): Promise<SubtitleResponse> {
    let path = `/subtitles/${type}/${id}`;
    if (extra && Object.keys(extra).length > 0) {
      const extraStr = Object.entries(extra)
        .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
        .join('&');
      path += `/${extraStr}`;
    }
    const response = await this.http.get(`${path}.json`);
    return response.data;
  }
}
