/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/

import { Entity } from '@/app/lib/definitions';
import { getCsrfToken, getSlug } from '@/app/lib/utils';


export interface Api<T extends Entity> {
  getAll(serializable: Serializable<T>, callback: (objets: T[]) => void): void;
  get(serializable: Serializable<T>, id: string, callback: (object: T) => void): void;
  create(serializable: Serializable<T>, object: T, callback: (object: T) => void): void;
  update(serializable: Serializable<T>, object: T, callback: () => void): void;
  destroy(serializable: Serializable<T>, object: T, callback: () => void): void;

  post(serializable: Serializable<T>, path: string, callback: () => void): void;
}

export interface Serializable<T> {
  fromJson(json: any): T;
  toJson(object: T): string;
  apiPath(): string;
}

export class AbstractApi<T extends Entity> implements Api<T> {
  getAll(serializable: Serializable<T>, callback: (objets: T[]) => void): void {
    fetch(`/api/${getSlug()}/${serializable.apiPath()}`)
      .then((response) => response.json())
      .then((data) => {
        callback(data.map((record: any) => {
          return serializable.fromJson(record);
        }));
      }, (error) => {
        return [];
      });
  }

  getAllPdf(serializable: Serializable<T>, callback: () => void): void {
    fetch(`/api/${getSlug()}/${serializable.apiPath()}`, {
      headers: {
        'Accept': 'application/pdf',
      }
    }).then(res => res.blob())
      .then(blob => {
        var file = window.URL.createObjectURL(blob);
        window.location.assign(file);
      });
  }

  get(serializable: Serializable<T>, id: (string | undefined), callback: (object: T) => void): void {
    const endpoint = id ? `/api/${getSlug()}/${serializable.apiPath()}/${id}` : `/api/${getSlug()}/${serializable.apiPath()}`;
    fetch(endpoint)
      .then((response) => response.json())
      .then((data) => {
        callback(serializable.fromJson(data));
      }, (error) => {
        return [];
      });
  }

  update(serializable: Serializable<T>, object: T, callback: (updatedObject: T) => void): void {
    const endpoint = object.id ? `/api/${getSlug()}/${serializable.apiPath()}/${object.id}` : `/api/${getSlug()}/${serializable.apiPath()}`;

    fetch(endpoint, {
      method: 'PUT',
      body: serializable.toJson(object),
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-CSRF-TOKEN': getCsrfToken(),
      }
    }).then((response) => response.json())
      .then((data) => {
        callback(serializable.fromJson(data));
      })
      .catch((error) => console.error(error));
  }

  create(serializable: Serializable<T>, object: T, callback: (createdObject: T) => void): void {
    fetch(`/api/${getSlug()}/${serializable.apiPath()}`, {
      method: 'POST',
      body: serializable.toJson(object),
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-CSRF-TOKEN': getCsrfToken(),
      }
    })
      .then((response) => response.json())
      .then((data) => {
        callback(serializable.fromJson(data));
      })
      .catch((error) => console.error(error));
  }

  destroy(serializable: Serializable<T>, object: T, callback: () => void): void {
    fetch(`/api/${getSlug()}/${serializable.apiPath()}/${object.id}`, {
      method: 'DELETE',
      headers: {
        'X-CSRF-TOKEN': getCsrfToken(),
      }
    }).then(callback)
      .catch((error) => console.error(error));
  }

  post(serializable: Serializable<T>, path: string, callback: () => void): void {
    fetch(`/api/${getSlug()}/${serializable.apiPath()}/${path}`, {
      method: 'POST',
      headers: {
        'X-CSRF-TOKEN': getCsrfToken(),
      }
    }).then(callback)
      .catch((error) => console.error(error));
  }
}
