import AsyncStorage from '@react-native-async-storage/async-storage';
import { useSyncExternalStore } from 'react';
import type { ChecklistState, ReportUpsert, WorkOrderStatus } from '@siop/shared';

/** La file d'écriture (D1) : chaque geste hors-ligne devient une saisie
 *  datée, persistée dans AsyncStorage — elle survit au redémarrage — et
 *  rejouée DANS L'ORDRE au retour du réseau. Chaque saisie porte la version
 *  de l'OT lue au moment du geste (D2, verrou optimiste). */

export type Saisie = {
  id: string;
  creeA: string; // ISO — affiché à l'écran Synchro
  otId: string;
  otReference: string;
  libelle: string; // « Coche “Jeu des coulisseaux” »
  baseUpdatedAt: string; // version lue (D2)
  statut: 'EN_ATTENTE' | 'ENVOI' | 'CONFLIT';
  erreur?: string; // message du 409 / refus métier — montré tel quel
} & (
  | { type: 'TRANSITION'; payload: { to: WorkOrderStatus } }
  | { type: 'COCHE'; payload: { itemId: string; state: ChecklistState } }
  | { type: 'BILAN'; payload: Omit<ReportUpsert, 'baseUpdatedAt'> }
  | { type: 'PHOTO'; payload: { uri: string; nom: string; mime: string } }
);

const CLE = 'siop.file.v1';
let file: Saisie[] = [];
const abonnes = new Set<() => void>();

function notifier(): void {
  for (const a of abonnes) a();
  void AsyncStorage.setItem(CLE, JSON.stringify(file));
}

/** À l'ouverture de l'app : la file survit au redémarrage (D1). */
export async function chargerFile(): Promise<void> {
  const brut = await AsyncStorage.getItem(CLE);
  if (brut) {
    // Un ENVOI interrompu par un crash redevient EN_ATTENTE (rejouable).
    file = (JSON.parse(brut) as Saisie[]).map((s) =>
      s.statut === 'ENVOI' ? { ...s, statut: 'EN_ATTENTE' } : s,
    );
    for (const a of abonnes) a();
  }
}

export const lireFile = (): Saisie[] => file;

export function enfiler(saisie: Omit<Saisie, 'id' | 'creeA' | 'statut'>): Saisie {
  const complete = {
    ...saisie,
    id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
    creeA: new Date().toISOString(),
    statut: 'EN_ATTENTE',
  } as Saisie;
  file = [...file, complete];
  notifier();
  return complete;
}

export function majSaisie(id: string, patch: Partial<Pick<Saisie, 'statut' | 'erreur' | 'baseUpdatedAt'>>): void {
  file = file.map((s) => (s.id === id ? ({ ...s, ...patch } as Saisie) : s));
  notifier();
}

export function retirer(id: string): void {
  file = file.filter((s) => s.id !== id);
  notifier();
}

export function useFile(): Saisie[] {
  return useSyncExternalStore(
    (cb) => {
      abonnes.add(cb);
      return () => abonnes.delete(cb);
    },
    lireFile,
    lireFile,
  );
}

/** Déconnexion : la file appartient à la SESSION — on la purge (sécurité :
 *  un autre compte sur le même téléphone ne doit jamais rejouer les saisies
 *  du précédent), avec sa persistance. */
export function viderFile(): void {
  file = [];
  notifier();
}

/** Réservé aux tests : repartir d'une file vide (sans persistance). */
export function _viderPourTests(): void {
  file = [];
}
