import HttpClient from '@/services/HttpClient';
import {
  Installation,
  InstallationDetail,
  InstallationSummary,
  InstallationValidation,
  Photo,
  PhotoType,
  ProvisioningState,
} from '@/models/teltoinstall/_index';

type Wrapped<T> = { data: T };
type MaybeWrapped<T> = T | Wrapped<T>;

function toProvisioningState(res: Partial<ProvisioningState>): ProvisioningState {
  return { status: res?.status ?? null, error: res?.error ?? null };
}

function unwrapObject<T>(res: MaybeWrapped<T>): T {
  if (res && typeof res === 'object' && 'data' in (res as object) && !Array.isArray(res)) {
    return (res as Wrapped<T>).data;
  }
  return res as T;
}

function unwrapArray<T>(res: MaybeWrapped<T[]>): T[] {
  if (Array.isArray(res)) return res;
  if (res && typeof res === 'object' && Array.isArray((res as Wrapped<T[]>).data)) {
    return (res as Wrapped<T[]>).data;
  }
  return [];
}

const InstallationRepository = {
  list() {
    return HttpClient.get<MaybeWrapped<InstallationSummary[]>>('/installations').then(
      unwrapArray<InstallationSummary>
    );
  },
  create() {
    return HttpClient.post<MaybeWrapped<Installation>>('/installations').then(unwrapObject<Installation>);
  },
  // Vérifie en temps réel (au blur du champ) qu'un IMEI existe chez Teltonika.
  // Toujours 200 : « found » / « not_found » / « error » (échec technique) — non
  // bloquant, l'app se contente d'afficher un retour sous le champ.
  verifyImei(imei: string) {
    return HttpClient.get<{ status: 'found' | 'not_found' | 'error' }>(
      `/devices/verify-imei/${imei}`
    ).then((r) => r.status);
  },
  // Démarre une pose à partir d'un véhicule d'une demande confirmée. Renvoie
  // `{ existing, installation }` : si `existing` est vrai (et `force` non passé),
  // une pose non validée existe déjà pour ce véhicule + boîtier — l'app propose
  // de la continuer ou d'en démarrer une nouvelle (`force: true`).
  createFromRequest(installationRequestId: number, vehicleId: number, force = false) {
    return HttpClient.post<{ existing: boolean; installation: MaybeWrapped<InstallationDetail> }>(
      '/installations/from-request',
      { installation_request_id: installationRequestId, vehicle_id: vehicleId, force }
    ).then((res) => ({
      existing: res.existing,
      installation: unwrapObject<InstallationDetail>(res.installation),
    }));
  },
  getById(id: number) {
    return HttpClient.get<MaybeWrapped<Installation>>(`/installations/${id}`).then(unwrapObject<Installation>);
  },
  getDetail(id: number) {
    return HttpClient.get<MaybeWrapped<InstallationDetail>>(`/installations/${id}`).then(
      unwrapObject<InstallationDetail>
    );
  },
  update(id: number, payload: Partial<Installation>) {
    return HttpClient.patch<MaybeWrapped<Installation>>(`/installations/${id}`, payload).then(unwrapObject<Installation>);
  },
  uploadPhotos(id: number, files: File[], type: PhotoType) {
    const formData = new FormData();
    files.forEach((f) => formData.append('files[]', f));
    formData.append('type', type);
    return HttpClient.postForm<MaybeWrapped<Photo[]>>(`/installations/${id}/photos`, formData).then(unwrapArray<Photo>);
  },
  deletePhoto(id: number, photoId: number) {
    return HttpClient.delete<void>(`/installations/${id}/photos/${photoId}`);
  },
  // Statut de provisionnement du boîtier (task Teltonika + device Flespi), joué
  // en tâche de fond. Interrogé en polling à l'étape « Validation » : le test de
  // connexion n'est proposé qu'une fois « provisioned ». En échec, `error` porte
  // la cause, affichée à l'installateur.
  provisioningStatus(id: number) {
    return HttpClient.get<Partial<ProvisioningState>>(`/installations/${id}/provisioning-status`).then(
      toProvisioningState
    );
  },
  // Relance la configuration du boîtier après un échec, sans ressaisir l'IMEI.
  retryProvisioning(id: number) {
    return HttpClient.post<Partial<ProvisioningState>>(`/installations/${id}/provisioning/retry`).then(
      toProvisioningState
    );
  },
  runGpsTest(id: number) {
    return HttpClient.post<MaybeWrapped<InstallationValidation>>(`/installations/${id}/gps-test`).then(unwrapObject<InstallationValidation>);
  },
  validate(id: number) {
    return HttpClient.post<MaybeWrapped<Installation>>(`/installations/${id}/validate`).then(unwrapObject<Installation>);
  },
};

export default InstallationRepository;
