import api from './api-client';

interface DeliveryEvidence {
  id: string;
  userId: number;
  photo: Blob | null;
  voice: Blob | null;
  transcript?: string;
  ocrText?: string;
  photoMeta?: unknown;
}

const DATABASE = 'gcx-delivery-evidence-outbox';
let syncPromise: Promise<void> | null = null;

async function withStore<T>(mode: IDBTransactionMode, action: (store: IDBObjectStore) => IDBRequest<T>): Promise<T> {
  const db = await new Promise<IDBDatabase>((resolve, reject) => {
    const request = indexedDB.open(DATABASE, 1);
    request.onupgradeneeded = () => request.result.createObjectStore('evidence', { keyPath: 'id' });
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
  });
  return new Promise((resolve, reject) => {
    const transaction = db.transaction('evidence', mode);
    const request = action(transaction.objectStore('evidence'));
    let result: T;
    request.onsuccess = () => { result = request.result; };
    transaction.oncomplete = () => { db.close(); resolve(result); };
    transaction.onerror = () => { db.close(); reject(transaction.error); };
    transaction.onabort = () => { db.close(); reject(transaction.error); };
  });
}

export async function queueDeliveryEvidence(input: Omit<DeliveryEvidence, 'userId'>): Promise<void> {
  if (!input.photo && !input.voice && !input.transcript && !input.ocrText && !input.photoMeta) return;
  const user = JSON.parse(localStorage.getItem('gcx_fshs_user') || 'null');
  if (!user?.id) throw new Error('Sign in before saving delivery evidence.');
  await withStore('readwrite', store => store.put({ ...input, userId: Number(user.id) }));
  if (navigator.onLine) void syncDeliveryEvidence().catch(() => undefined);
}

export async function syncDeliveryEvidence(): Promise<void> {
  if (syncPromise) return syncPromise;
  syncPromise = (async () => {
    if (!navigator.onLine) return;
    const entries = await withStore<DeliveryEvidence[]>('readonly', store => store.getAll());
    if (entries.length === 0) return;
    const me = (await api.get('/auth/me')).data.user;
    for (const entry of entries) {
      if (Number(me?.id) !== entry.userId) continue;
      try {
        let deliveryId = Number(entry.id);
        if (!Number.isInteger(deliveryId) || deliveryId <= 0) {
          const resolved = await api.get('/deliveries/client-submission/' + encodeURIComponent(entry.id));
          deliveryId = Number(resolved.data.delivery_id);
        }
        const form = new FormData();
        if (entry.photo) form.append('photo', entry.photo, 'photo');
        if (entry.voice) form.append('voice', entry.voice, 'voice');
        if (entry.transcript) form.append('voice_transcript', entry.transcript);
        if (entry.ocrText) form.append('ocr_text', entry.ocrText);
        if (entry.photoMeta) form.append('photo_meta', JSON.stringify(entry.photoMeta));
        await api.post('/deliveries/' + deliveryId + '/evidence', form, { timeout: 60_000 });
        await withStore('readwrite', store => store.delete(entry.id));
      } catch (error: any) {
        if (!error.response || error.response.status === 401 || error.response.status >= 500) break;
      }
    }
  })().finally(() => { syncPromise = null; });
  return syncPromise;
}
