// @ts-nocheck
import { withStore } from './idb';
import { getDeviceId } from '../lib/device';
import { createUpload } from './xhr';
import { notify } from './notify';
type SyncManager = { register(tag: string): Promise<void>; };

export type QueueItem = {
  id?: number;
  eventToken: string;
  fileName: string;
  blob: Blob;
  emotion_id?: number | null;
  task_id?: number | null;
  live_show_opt_in?: boolean | null;
  status: 'pending' | 'uploading' | 'done' | 'error';
  retries: number;
  nextAttemptAt?: number | null;
  createdAt: number;
  photoId?: number;
};

let processing = false;

export async function enqueue(item: Omit<QueueItem, 'id' | 'status' | 'retries' | 'createdAt'>) {
  const now = Date.now();
  await withStore('readwrite', (store) => {
    store.add({ ...item, status: 'pending', retries: 0, createdAt: now });
  });
  // Register background sync if available
  if ('serviceWorker' in navigator && 'SyncManager' in window) {
    try {
      const reg = await navigator.serviceWorker.ready;
      (reg as ServiceWorkerRegistration & { sync?: SyncManager }).sync?.register('upload-queue');
    } catch (error) {
      console.warn('Background sync registration failed', error);
    }
  }
}

export async function list(): Promise<QueueItem[]> {
  return withStore('readonly', (store) => new Promise((resolve) => {
    const req = store.getAll();
    req.onsuccess = () => resolve(req.result as QueueItem[]);
  }));
}

export async function clearDone() {
  const items = await list();
  await withStore('readwrite', (store) => {
    for (const it of items) {
      if (it.status === 'done') store.delete(it.id!);
    }
  });
}

export async function processQueue() {
  if (processing) return; processing = true;
  try {
    const now = Date.now();
    const items = await list();
    for (const it of items) {
      if (it.status === 'done') continue;
      if (it.nextAttemptAt && it.nextAttemptAt > now) continue;
      await markStatus(it.id!, 'uploading');
      const ok = await attemptUpload(it);
      if (ok) {
        await markStatus(it.id!, 'done');
      } else {
        const retries = (it.retries ?? 0) + 1;
        const backoffSec = Math.min(60, Math.pow(2, Math.min(retries, 5))); // 2,4,8,16,32,60
        await update(it.id!, { status: 'error', retries, nextAttemptAt: Date.now() + backoffSec * 1000 });
      }
    }
  } finally {
    processing = false;
  }
}

async function attemptUpload(it: QueueItem): Promise<boolean> {
  if (!navigator.onLine) return false;
  try {
    const json = await createUpload(
      `/api/v1/events/${encodeURIComponent(it.eventToken)}/photos`,
      it,
      getDeviceId(),
      (pct) => {
        try {
          window.dispatchEvent(new CustomEvent('queue-progress', { detail: { id: it.id, progress: pct } }));
        } catch (error) {
          console.warn('Queue progress dispatch failed', error);
        }
      }
    );
    // mark my-photo-ids for "Meine"
    try {
      const raw = localStorage.getItem('my-photo-ids');
      const arr: number[] = raw ? JSON.parse(raw) : [];
      if (json.id && !arr.includes(json.id)) localStorage.setItem('my-photo-ids', JSON.stringify([json.id, ...arr]));
    } catch (error) {
      console.warn('Failed to persist my-photo-ids', error);
    }
    notify('Upload erfolgreich', 'success');
    return true;
  } catch {
    notify('Upload fehlgeschlagen', 'error');
    return false;
  }
}

async function markStatus(id: number, status: QueueItem['status']) {
  await update(id, { status });
}

async function update(id: number, patch: Partial<QueueItem>) {
  await withStore('readwrite', (store) => new Promise<void>((resolve, reject) => {
    const getReq = store.get(id);
    getReq.onsuccess = () => {
      const val = getReq.result as QueueItem;
      store.put({ ...val, ...patch, id });
      resolve();
    };
    getReq.onerror = () => reject(getReq.error);
  }));
}
