/**
 * Submission Queue with IndexedDB Fallback
 * 
 * Provides resilience when edge functions are unavailable by queuing
 * submissions locally and retrying when connectivity is restored.
 * 
 * Part of Sacred Pipeline Phase 3: Fortify Defenses
 */

import { openDB, DBSchema, IDBPDatabase } from 'idb';

interface SubmissionQueueDB extends DBSchema {
  submissions: {
    key: string;
    value: {
      id: string;
      type: string;
      data: any;
      timestamp: number;
      retries: number;
      lastAttempt: number | null;
      error: string | null;
    };
  };
}

const DB_NAME = 'thrillwiki-submission-queue';
const DB_VERSION = 1;
const STORE_NAME = 'submissions';
const MAX_RETRIES = 3;

let dbInstance: IDBPDatabase<SubmissionQueueDB> | null = null;

async function getDB(): Promise<IDBPDatabase<SubmissionQueueDB>> {
  if (dbInstance) return dbInstance;

  dbInstance = await openDB<SubmissionQueueDB>(DB_NAME, DB_VERSION, {
    upgrade(db) {
      if (!db.objectStoreNames.contains(STORE_NAME)) {
        db.createObjectStore(STORE_NAME, { keyPath: 'id' });
      }
    },
  });

  return dbInstance;
}

/**
 * Queue a submission for later processing
 */
export async function queueSubmission(type: string, data: any): Promise<string> {
  const db = await getDB();
  const id = crypto.randomUUID();

  await db.add(STORE_NAME, {
    id,
    type,
    data,
    timestamp: Date.now(),
    retries: 0,
    lastAttempt: null,
    error: null,
  });

  console.info(`[SubmissionQueue] Queued ${type} submission ${id}`);
  return id;
}

/**
 * Get all pending submissions
 */
export async function getPendingSubmissions() {
  const db = await getDB();
  return await db.getAll(STORE_NAME);
}

/**
 * Get count of pending submissions
 */
export async function getPendingCount(): Promise<number> {
  const db = await getDB();
  const all = await db.getAll(STORE_NAME);
  return all.length;
}

/**
 * Remove a submission from the queue
 */
export async function removeFromQueue(id: string): Promise<void> {
  const db = await getDB();
  await db.delete(STORE_NAME, id);
  console.info(`[SubmissionQueue] Removed submission ${id}`);
}

/**
 * Update submission retry count and error
 */
export async function updateSubmissionRetry(
  id: string, 
  error: string
): Promise<void> {
  const db = await getDB();
  const item = await db.get(STORE_NAME, id);
  
  if (!item) return;

  item.retries += 1;
  item.lastAttempt = Date.now();
  item.error = error;

  await db.put(STORE_NAME, item);
}

/**
 * Process all queued submissions
 * Called when connectivity is restored or on app startup
 */
export async function processQueue(
  submitFn: (type: string, data: any) => Promise<void>
): Promise<{ processed: number; failed: number }> {
  const db = await getDB();
  const pending = await db.getAll(STORE_NAME);
  
  let processed = 0;
  let failed = 0;

  for (const item of pending) {
    try {
      console.info(`[SubmissionQueue] Processing ${item.type} submission ${item.id} (attempt ${item.retries + 1})`);
      
      await submitFn(item.type, item.data);
      await db.delete(STORE_NAME, item.id);
      processed++;
      
      console.info(`[SubmissionQueue] Successfully processed ${item.id}`);
    } catch (error) {
      const errorMsg = error instanceof Error ? error.message : String(error);
      
      if (item.retries >= MAX_RETRIES - 1) {
        // Max retries exceeded, remove from queue
        await db.delete(STORE_NAME, item.id);
        failed++;
        console.error(`[SubmissionQueue] Max retries exceeded for ${item.id}:`, errorMsg);
      } else {
        // Update retry count
        await updateSubmissionRetry(item.id, errorMsg);
        console.warn(`[SubmissionQueue] Retry ${item.retries + 1}/${MAX_RETRIES} failed for ${item.id}:`, errorMsg);
      }
    }
  }

  return { processed, failed };
}

/**
 * Clear all queued submissions (use with caution!)
 */
export async function clearQueue(): Promise<number> {
  const db = await getDB();
  const tx = db.transaction(STORE_NAME, 'readwrite');
  const store = tx.objectStore(STORE_NAME);
  const all = await store.getAll();
  
  await store.clear();
  await tx.done;

  console.warn(`[SubmissionQueue] Cleared ${all.length} submissions from queue`);
  return all.length;
}

/**
 * Check if edge function is available
 */
export async function checkEdgeFunctionHealth(
  functionUrl: string
): Promise<boolean> {
  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 5000);

    const response = await fetch(functionUrl, {
      method: 'HEAD',
      signal: controller.signal,
    });

    clearTimeout(timeout);
    return response.ok || response.status === 405; // 405 = Method Not Allowed is OK
  } catch (error) {
    console.error('[SubmissionQueue] Health check failed:', error);
    return false;
  }
}
