// lib/og-image-generator.tsx
import { getDealerDisplayName } from '@/lib/dealer-display-name';
import { getFirstActiveSlideImageUrl, SliderContent } from '@/types/slider';

export interface OgImageConfig {
  businessName?: string | null;
  logoUrl?: string | null;
  contactName?: string | null;
  showContactName?: boolean | null;
  city?: string | null;
  state?: string | null;
  hideAddress?: boolean | null;
  heroImageUrl?: string | null;
}

export interface OgImageParams {
  showAmsoilLogo: boolean;
  dealerLogoUrl?: string;
  businessName: string;
  contactName?: string;
  location?: string;
  heroImageUrl: string;
}

const DEFAULT_HERO_IMAGE = '/images/slider-defaults/hero-1.jpg';

/**
 * Legacy flat array format for backward compatibility.
 * Some older data may have this format.
 */
export interface HeroSlide {
  imageUrl?: string;
  image?: string;
  src?: string;
}

/** Shape-only check: validates slides array, not id/updatedAt. */
function isSliderContent(value: unknown): value is SliderContent {
  return (
    typeof value === 'object' &&
    value !== null &&
    'slides' in value &&
    Array.isArray((value as { slides: unknown }).slides)
  );
}

/**
 * Type guard for legacy HeroSlide array format
 */
function isHeroSlideArray(value: unknown): value is HeroSlide[] {
  return Array.isArray(value) && value.length > 0 && typeof value[0] === 'object';
}

/**
 * Get the hero image URL from slider content or page content.
 * Handles both the modern SliderContent format ({ slides: [{ image: { url } }] })
 * and legacy flat array format ([{ imageUrl }]).
 *
 * Accepts unknown to be compatible with Prisma JsonValue type.
 */
export function getHeroImageUrl(heroSlider: unknown, pageContent: unknown): string {
  // Try page content first (for CMS pages)
  if (pageContent) {
    const pageImage = extractFirstImageFromPageContent(pageContent);
    if (pageImage) return pageImage;
  }

  // Then try hero slider
  if (heroSlider) {
    // Handle modern SliderContent format: { slides: [{ image: { url } }] }
    if (isSliderContent(heroSlider)) {
      const imageUrl = getFirstActiveSlideImageUrl(heroSlider);
      if (imageUrl) return imageUrl;
    }

    // Handle legacy flat array format: [{ imageUrl }]
    if (isHeroSlideArray(heroSlider)) {
      const firstSlide = heroSlider[0];
      const imageUrl = firstSlide.imageUrl || firstSlide.image || firstSlide.src;
      if (imageUrl) return imageUrl;
    }
  }

  // Fallback to default
  return DEFAULT_HERO_IMAGE;
}

// Maximum recursion depth to prevent stack overflow with malformed content
const MAX_RECURSION_DEPTH = 50;

export function extractFirstImageFromPageContent(content: unknown): string | null {
  if (!content || typeof content !== 'object') return null;

  const imageProps = ['imageUrl', 'image', 'src', 'backgroundImage'];

  function findImage(obj: unknown, depth: number = 0): string | null {
    // Prevent stack overflow with deeply nested or circular structures
    if (depth > MAX_RECURSION_DEPTH || !obj || typeof obj !== 'object') return null;

    const record = obj as Record<string, unknown>;

    // Check direct image properties
    for (const prop of imageProps) {
      if (typeof record[prop] === 'string' && record[prop]) {
        const url = record[prop] as string;
        if (url.startsWith('https://') || url.startsWith('http://') || url.startsWith('/')) {
          return url;
        }
      }
    }

    // Check props object
    if (record.props && typeof record.props === 'object') {
      const found = findImage(record.props, depth + 1);
      if (found) return found;
    }

    // Check children array
    if (Array.isArray(record.children)) {
      for (const child of record.children) {
        const found = findImage(child, depth + 1);
        if (found) return found;
      }
    }

    // Check content array
    if (Array.isArray(record.content)) {
      for (const item of record.content) {
        const found = findImage(item, depth + 1);
        if (found) return found;
      }
    }

    return null;
  }

  return findImage(content, 0);
}

export function buildOgImageParams(config: OgImageConfig): OgImageParams {
  // getDealerDisplayName gates the contactName fallback on showContactName
  // itself. OgImageConfig is built from external sources where the field may
  // be absent, so the optional field is normalized to the privacy-safe
  // default before it meets the helper's required input.
  const displayName = getDealerDisplayName({
    businessName: config.businessName,
    contactName: config.contactName,
    showContactName: config.showContactName ?? false,
  });
  const params: OgImageParams = {
    showAmsoilLogo: true,
    businessName: displayName,
    heroImageUrl: config.heroImageUrl || DEFAULT_HERO_IMAGE,
  };

  // Dealer logo - only if set
  if (config.logoUrl) {
    params.dealerLogoUrl = config.logoUrl;
  }

  // Contact name - only if showContactName is true and not already used as display name
  if (config.showContactName && config.contactName && displayName !== config.contactName) {
    params.contactName = config.contactName;
  }

  // Location - only if hideAddress is false
  if (!config.hideAddress && config.city && config.state) {
    params.location = `${config.city}, ${config.state}`;
  }

  return params;
}
