/**
 * Image Generation Queue Management
 *
 * Handles batch processing of image generation requests.
 * Ported from Python ws/image_generation.py queue operations.
 */

import { getPool } from '../../database/pool.js';
import { config } from '../../config.js';
import { ImageGenerator, type ImageProvider } from './image_generator.js';
import { saveGeneratedImage, type QueueItem } from './database.js';
import type { RowDataPacket, ResultSetHeader } from 'mysql2';

// ============================================================
// Queue Operations
// ============================================================

/**
 * Add image generation request to queue
 */
export async function addToGenerationQueue(options: {
  prompt: string;
  eventType?: string;
  eventCategory?: string;
  stylePreset?: string;
  priority?: number;
  provider?: ImageProvider;
}): Promise<number | null> {
  const {
    prompt,
    eventType = null,
    eventCategory = null,
    stylePreset = 'cozy_cartoon',
    priority = 5,
    provider = config.IMAGE_GENERATION_PROVIDER,
  } = options;

  const pool = getPool();

  try {
    const [result] = await pool.execute<ResultSetHeader>(
      `INSERT INTO image_generation_queue
       (prompt, style_preset, event_type, event_category, priority, provider)
       VALUES (?, ?, ?, ?, ?, ?)`,
      [prompt, stylePreset, eventType, eventCategory, priority, provider]
    );

    const queueId = result.insertId;
    console.log(`Added to generation queue: ${queueId}`);
    return queueId;
  } catch (e) {
    console.error(`Failed to add to generation queue: ${e}`);
    return null;
  }
}

/**
 * Get pending queue items
 */
export async function getPendingQueueItems(limit: number = 10): Promise<QueueItem[]> {
  const pool = getPool();

  try {
    const [rows] = await pool.execute<RowDataPacket[]>(
      `SELECT * FROM image_generation_queue
       WHERE status = 'pending' AND attempts < max_attempts
       ORDER BY priority DESC, created_at ASC
       LIMIT ?`,
      [limit]
    );

    return rows as QueueItem[];
  } catch (e) {
    console.error(`Failed to get pending queue items: ${e}`);
    return [];
  }
}

/**
 * Update queue item status
 */
async function updateQueueStatus(
  itemId: number,
  status: 'pending' | 'processing' | 'completed' | 'failed',
  additionalFields?: {
    errorMessage?: string;
    generatedImageId?: number;
  }
): Promise<void> {
  const pool = getPool();

  let query = 'UPDATE image_generation_queue SET status = ?, updated_at = NOW()';
  const params: (string | number | null)[] = [status];

  if (status === 'processing') {
    query += ', attempts = attempts + 1';
  }

  if (status === 'completed') {
    query += ', completed_at = NOW()';
  }

  if (additionalFields?.errorMessage) {
    query += ', error_message = ?';
    params.push(additionalFields.errorMessage);
  }

  if (additionalFields?.generatedImageId) {
    query += ', generated_image_id = ?';
    params.push(additionalFields.generatedImageId);
  }

  query += ' WHERE id = ?';
  params.push(itemId);

  await pool.execute(query, params);
}

/**
 * Process a single queue item
 */
export async function processQueueItem(item: QueueItem): Promise<boolean> {
  try {
    // Update status to processing
    await updateQueueStatus(item.id, 'processing');

    // Generate image
    const generator = new ImageGenerator(item.provider);
    const result = await generator.generateImage(item.prompt, {
      style: item.style_preset,
    });

    if (result.imageUrl) {
      // Save to generated_images
      const imageId = await saveGeneratedImage({
        imageUrl: result.imageUrl,
        prompt: item.prompt,
        provider: item.provider,
        eventType: item.event_type ?? undefined,
        eventCategory: item.event_category ?? undefined,
        stylePreset: item.style_preset,
      });

      // Update queue item as completed
      await updateQueueStatus(item.id, 'completed', {
        generatedImageId: imageId ?? undefined,
      });

      console.log(`Queue item ${item.id} completed successfully`);
      return true;
    } else {
      // Mark as failed
      await updateQueueStatus(item.id, 'failed', {
        errorMessage: result.error ?? 'Unknown error',
      });

      console.error(`Queue item ${item.id} failed: ${result.error}`);
      return false;
    }
  } catch (e) {
    console.error(`Failed to process queue item ${item.id}: ${e}`);
    await updateQueueStatus(item.id, 'failed', {
      errorMessage: e instanceof Error ? e.message : String(e),
    });
    return false;
  }
}

/**
 * Process pending image generation requests from queue
 */
export async function processGenerationQueue(batchSize: number = 10): Promise<{
  processed: number;
  successful: number;
  failed: number;
}> {
  const items = await getPendingQueueItems(batchSize);

  if (items.length === 0) {
    console.log('No pending images in queue');
    return { processed: 0, successful: 0, failed: 0 };
  }

  console.log(`Processing ${items.length} images from queue`);

  let successful = 0;
  let failed = 0;

  for (const item of items) {
    const success = await processQueueItem(item);
    if (success) {
      successful++;
    } else {
      failed++;
    }

    // Wait between requests to avoid rate limiting
    await new Promise(resolve => setTimeout(resolve, 2000));
  }

  return {
    processed: items.length,
    successful,
    failed,
  };
}

/**
 * Get queue statistics
 */
export async function getQueueStats(): Promise<{
  pending: number;
  processing: number;
  completed: number;
  failed: number;
}> {
  const pool = getPool();

  try {
    const [rows] = await pool.execute<RowDataPacket[]>(
      `SELECT status, COUNT(*) as count
       FROM image_generation_queue
       GROUP BY status`
    );

    const stats = { pending: 0, processing: 0, completed: 0, failed: 0 };

    for (const row of rows) {
      if (row.status in stats) {
        stats[row.status as keyof typeof stats] = row.count;
      }
    }

    return stats;
  } catch (e) {
    console.error(`Failed to get queue stats: ${e}`);
    return { pending: 0, processing: 0, completed: 0, failed: 0 };
  }
}

/**
 * Clear completed queue items older than specified days
 */
export async function clearOldQueueItems(daysOld: number = 7): Promise<number> {
  const pool = getPool();

  try {
    const [result] = await pool.execute<ResultSetHeader>(
      `DELETE FROM image_generation_queue
       WHERE status IN ('completed', 'failed')
       AND completed_at < DATE_SUB(NOW(), INTERVAL ? DAY)`,
      [daysOld]
    );

    console.log(`Cleared ${result.affectedRows} old queue items`);
    return result.affectedRows;
  } catch (e) {
    console.error(`Failed to clear old queue items: ${e}`);
    return 0;
  }
}

/**
 * Retry failed queue items
 */
export async function retryFailedItems(): Promise<number> {
  const pool = getPool();

  try {
    const [result] = await pool.execute<ResultSetHeader>(
      `UPDATE image_generation_queue
       SET status = 'pending', error_message = NULL, updated_at = NOW()
       WHERE status = 'failed' AND attempts < max_attempts`
    );

    console.log(`Reset ${result.affectedRows} failed items for retry`);
    return result.affectedRows;
  } catch (e) {
    console.error(`Failed to retry failed items: ${e}`);
    return 0;
  }
}
