/**
 * Brand Logo Resolution
 *
 * One answer to "what is this company's logo?", shared by every module that
 * needs to put the real logo on something it generates (Stationery templates,
 * HR asset templates, image overlays).
 *
 * The logo is ALWAYS resolved from the Brand Assets the company actually
 * uploaded or generated — no module invents one, and no module gets to disagree
 * with another about which asset is primary.
 *
 * Extracted from the Stationery generation path in routes/imageGenerations.ts,
 * unchanged, so both callers share a single definition.
 */

import fs from 'fs';
import path from 'path';
import { getModels } from '../models';

/**
 * Read a brand asset's image bytes (from its inline base64Data or its uploaded
 * file) so the logo can be composited directly onto a generated image.
 * Returns null when no usable image is found.
 */
export async function readBrandAssetImageBytes(asset: any): Promise<{ buffer: Buffer; mimeType: string } | null> {
  try {
    if (asset?.base64Data) {
      const dataUriMatch = String(asset.base64Data).match(/^data:([^;]+);base64,(.+)$/s);
      if (dataUriMatch) {
        return { buffer: Buffer.from(dataUriMatch[2], 'base64'), mimeType: dataUriMatch[1] };
      }
      return { buffer: Buffer.from(String(asset.base64Data), 'base64'), mimeType: 'image/png' };
    }
    if (asset?.url && typeof asset.url === 'string') {
      const filePath = asset.url.startsWith('/uploads/brand-assets/')
        ? path.resolve(process.cwd(), 'uploads', 'brand-assets', path.basename(asset.url))
        : path.resolve(process.cwd(), asset.url.replace(/^\//, ''));
      if (!fs.existsSync(filePath)) return null;
      const buffer = await fs.promises.readFile(filePath);
      const ext = path.extname(filePath).toLowerCase();
      const mimeType =
        ext === '.jpg' || ext === '.jpeg' ? 'image/jpeg'
        : ext === '.webp' ? 'image/webp'
        : ext === '.svg' ? 'image/svg+xml'
        : 'image/png';
      return { buffer, mimeType };
    }
    return null;
  } catch (e) {
    console.warn('[BrandLogo] Failed to read brand asset image:', (e as Error).message);
    return null;
  }
}

/**
 * Find the company's actual uploaded brand logo (from Brand Assets). We NEVER
 * let AI invent a logo — this resolves the real asset. Returns undefined only
 * when no usable logo exists.
 */
export async function resolvePrimaryLogoAssetId(companyId: string): Promise<string | undefined> {
  try {
    const { BrandAsset } = getModels();
    // Real logo asset types from the BrandAsset model.
    const logoTypes = ['logo', 'logoHorizontal', 'logoVertical', 'logoMarkLight', 'logoMarkDark', 'wordmark', 'secondary-logo', 'logo-icon', 'logoIconOnly'];
    const usable = (a: any) => !!a && (!!a.base64Data || !!a.url);
    const candidates: any[] = await (BrandAsset as any).find({ companyId, type: { $in: logoTypes } }).lean();
    const pick =
      candidates.find((a) => a.isPrimary && (a.type === 'logo' || a.type === 'logoHorizontal') && usable(a)) ||
      candidates.find((a) => a.isPrimary && usable(a)) ||
      candidates.find((a) => a.type === 'logo' && usable(a)) ||
      candidates.find((a) => a.type === 'logoHorizontal' && usable(a)) ||
      candidates.find((a) => usable(a));
    if (pick) return String(pick._id);
    // Last resort: any brand asset whose name mentions "logo".
    const byName = await (BrandAsset as any).findOne({ companyId, name: { $regex: 'logo', $options: 'i' } }).lean();
    if (usable(byName)) return String(byName._id);
    console.warn(`[BrandLogo] No usable brand logo found for company ${companyId} — the design will be generated without a logo.`);
    return undefined;
  } catch {
    return undefined;
  }
}

/**
 * The company's real logo as a self-contained data URI, so an HTML template can
 * be opened on its own and still show the logo. Empty string when no usable
 * logo exists — the template then simply omits the image.
 */
export async function resolveBrandLogoDataUri(companyId: string): Promise<string> {
  try {
    const assetId = await resolvePrimaryLogoAssetId(companyId);
    if (!assetId) return '';
    const { BrandAsset } = getModels();
    const asset = await (BrandAsset as any).findOne({ _id: assetId, companyId });
    const bytes = asset ? await readBrandAssetImageBytes(asset) : null;
    if (!bytes) return '';
    return `data:${bytes.mimeType};base64,${bytes.buffer.toString('base64')}`;
  } catch {
    return '';
  }
}
