/**
 * Prompt Config Loader
 *
 * Loads image generation prompt configurations from MongoDB.
 * Falls back to hardcoded defaults when MongoDB is unavailable
 * or when no active documents exist for a type.
 *
 * This ensures the system always works even if MongoDB is down.
 */

import { getModels } from '../../models';
import {
  STYLE_GUIDANCE,
  PLATFORM_GUIDANCE,
  ASSET_CATEGORY_GUIDANCE,
  ASSET_CONTENT_ELEMENTS,
} from './imageGenerationPrompts';

// ============================================
// TYPES
// ============================================

interface PlatformGuidanceValue {
  usage: string;
  tips: string;
}

// ============================================
// CACHED PROMPTS (in-memory cache for performance)
// ============================================

let cachedStyleGuidance: Record<string, string> | null = null;
let cachedPlatformGuidance: Record<string, PlatformGuidanceValue> | null = null;
let cachedAssetCategoryGuidance: Record<string, string> | null = null;
let cachedAssetContentElements: Record<string, string> | null = null;
let cacheExpiry = 0;
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

function isCacheValid(): boolean {
  return Date.now() < cacheExpiry;
}

/**
 * Invalidate the prompt cache.
 * Call after updating prompts from the admin panel.
 */
export function invalidatePromptCache(): void {
  cachedStyleGuidance = null;
  cachedPlatformGuidance = null;
  cachedAssetCategoryGuidance = null;
  cachedAssetContentElements = null;
  cacheExpiry = 0;
}

// ============================================
// LOADER FUNCTIONS
// ============================================

/**
 * Load style guidance from MongoDB, falling back to hardcoded defaults.
 */
export async function getStyleGuidance(): Promise<Record<string, string>> {
  if (cachedStyleGuidance && isCacheValid()) return cachedStyleGuidance;

  try {
    const PromptConfig = getModels().PromptConfig;
    const docs = await PromptConfig.find({ type: 'style_guidance', isActive: true }).lean();
    if (docs.length > 0) {
      const result: Record<string, string> = {};
      for (const doc of docs) {
        result[doc.key] = doc.prompt;
      }
      cachedStyleGuidance = result;
      cacheExpiry = Date.now() + CACHE_TTL;
      return result;
    }
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading style guidance from MongoDB, using defaults:', error);
  }

  cachedStyleGuidance = { ...STYLE_GUIDANCE };
  cacheExpiry = Date.now() + CACHE_TTL;
  return cachedStyleGuidance;
}

/**
 * Load platform guidance from MongoDB, falling back to hardcoded defaults.
 */
export async function getPlatformGuidance(): Promise<Record<string, PlatformGuidanceValue>> {
  if (cachedPlatformGuidance && isCacheValid()) return cachedPlatformGuidance;

  try {
    const PromptConfig = getModels().PromptConfig;
    const docs = await PromptConfig.find({ type: 'platform_guidance', isActive: true }).lean();
    if (docs.length > 0) {
      const result: Record<string, PlatformGuidanceValue> = {};
      for (const doc of docs) {
        // Parse the stored prompt back into usage + tips
        // Stored format: "Usage: <usage>. Tips: <tips>"
        const usageMatch = doc.prompt.match(/^Usage:\s*(.+?)\.\s*Tips:\s*(.+)$/s);
        if (usageMatch) {
          result[doc.key] = { usage: usageMatch[1], tips: usageMatch[2] };
        } else {
          // Fallback: use the whole prompt as usage
          const defaultEntry = PLATFORM_GUIDANCE[doc.key] || PLATFORM_GUIDANCE.Other;
          result[doc.key] = { usage: defaultEntry?.usage || doc.prompt, tips: defaultEntry?.tips || '' };
        }
      }
      cachedPlatformGuidance = result;
      cacheExpiry = Date.now() + CACHE_TTL;
      return result;
    }
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading platform guidance from MongoDB, using defaults:', error);
  }

  cachedPlatformGuidance = { ...PLATFORM_GUIDANCE };
  cacheExpiry = Date.now() + CACHE_TTL;
  return cachedPlatformGuidance;
}

/**
 * Load asset category guidance from MongoDB, falling back to hardcoded defaults.
 */
export async function getAssetCategoryGuidance(): Promise<Record<string, string>> {
  if (cachedAssetCategoryGuidance && isCacheValid()) return cachedAssetCategoryGuidance;

  try {
    const PromptConfig = getModels().PromptConfig;
    const docs = await PromptConfig.find({ type: 'asset_category_guidance', isActive: true }).lean();
    if (docs.length > 0) {
      const result: Record<string, string> = {};
      for (const doc of docs) {
        result[doc.key] = doc.prompt;
      }
      cachedAssetCategoryGuidance = result;
      cacheExpiry = Date.now() + CACHE_TTL;
      return result;
    }
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading asset category guidance from MongoDB, using defaults:', error);
  }

  cachedAssetCategoryGuidance = { ...ASSET_CATEGORY_GUIDANCE };
  cacheExpiry = Date.now() + CACHE_TTL;
  return cachedAssetCategoryGuidance;
}

/**
 * Load asset content elements from MongoDB, falling back to hardcoded defaults.
 */
export async function getAssetContentElements(): Promise<Record<string, string>> {
  if (cachedAssetContentElements && isCacheValid()) return cachedAssetContentElements;

  try {
    const PromptConfig = getModels().PromptConfig;
    const docs = await PromptConfig.find({ type: 'asset_content_elements', isActive: true }).lean();
    if (docs.length > 0) {
      const result: Record<string, string> = {};
      for (const doc of docs) {
        result[doc.key] = doc.prompt;
      }
      cachedAssetContentElements = result;
      cacheExpiry = Date.now() + CACHE_TTL;
      return result;
    }
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading asset content elements from MongoDB, using defaults:', error);
  }

  cachedAssetContentElements = { ...ASSET_CONTENT_ELEMENTS };
  cacheExpiry = Date.now() + CACHE_TTL;
  return cachedAssetContentElements;
}

/**
 * Get a single prompt config value by type and key.
 * Returns null if not found or inactive.
 */
export async function getPromptConfig(type: string, key: string): Promise<string | null> {
  try {
    const PromptConfig = getModels().PromptConfig;
    const doc = await PromptConfig.findOne({ type, key, isActive: true }).lean();
    return doc ? doc.prompt : null;
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading prompt config:', error);
    return null;
  }
}

/**
 * Get all active prompt variants for a given type and key.
 * Returns an array of IPromptConfig documents.
 * Used by the prompt selection UI to show available variants.
 */
export async function getPromptVariants(type: string, key: string): Promise<any[]> {
  try {
    const PromptConfig = getModels().PromptConfig;
    const docs = await PromptConfig.find({ type, key, isActive: true })
      .sort({ isDefaultVariant: -1, name: 1 })
      .lean();
    return docs;
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading prompt variants:', error);
    return [];
  }
}

/**
 * Get the default prompt variant for a given type and key.
 * Returns the prompt string of the default variant, or null if not found.
 */
export async function getDefaultPromptVariant(type: string, key: string): Promise<string | null> {
  try {
    const PromptConfig = getModels().PromptConfig;
    const doc = await PromptConfig.findOne({ type, key, isActive: true, isDefaultVariant: true }).lean();
    if (doc) return doc.prompt;
    // Fallback: if no isDefaultVariant, get the first active one
    const fallback = await PromptConfig.findOne({ type, key, isActive: true }).lean();
    return fallback ? fallback.prompt : null;
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading default prompt variant:', error);
    return null;
  }
}

/**
 * Get a specific prompt variant by its MongoDB _id.
 * Returns the full document or null.
 */
export async function getPromptVariantById(id: string): Promise<any | null> {
  try {
    const PromptConfig = getModels().PromptConfig;
    const doc = await PromptConfig.findById(id).lean();
    return doc;
  } catch (error) {
    console.error('[PromptConfigLoader] Error loading prompt variant by ID:', error);
    return null;
  }
}