import { MetaBatchItemRequest, MetaBatchItemPayload, VariantExportMode, PriceMode } from '@/types/catalog';
import { ShopifyProduct, ShopifyVariant } from '@/lib/shopify/product-service';
import { resolveProductCategory } from '@/lib/shopify/client';

export interface ItemMapperOptions {
  variantExportMode: VariantExportMode;
  googleCategory?: string;
  imageOption: 'first' | 'all';
  productLinkDomain: 'primary' | 'myshopify' | 'custom';
  customDomain?: string;
  shopDomain: string; // e.g. "quickstart-1a79b82e.myshopify.com"
  primaryDomain?: string; // e.g. "mystore.com"
  currency: string;
  priceMode?: PriceMode;
}

/**
 * Strips HTML tags, decodes HTML entities, and normalizes whitespace for Meta Catalog descriptions.
 */
export function cleanHtmlDescription(html?: string): string {
  if (!html) return '';
  return html
    .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
    .replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '')
    .replace(/<br\s*[\/]?>/gi, '\n')
    .replace(/<\/p>/gi, '\n\n')
    .replace(/<\/li>/gi, '\n')
    .replace(/<\/h[1-6]>/gi, '\n\n')
    .replace(/<[^>]*>/g, ' ')
    .replace(/&nbsp;/gi, ' ')
    .replace(/&amp;/gi, '&')
    .replace(/&quot;/gi, '"')
    .replace(/&#39;/gi, "'")
    .replace(/&apos;/gi, "'")
    .replace(/&lt;/gi, '<')
    .replace(/&gt;/gi, '>')
    .replace(/&#x27;/gi, "'")
    .replace(/&#x2F;/gi, '/')
    .replace(/&rsquo;/gi, "'")
    .replace(/&lsquo;/gi, "'")
    .replace(/&ldquo;/gi, '"')
    .replace(/&rdquo;/gi, '"')
    .replace(/&ndash;/gi, '-')
    .replace(/&mdash;/gi, '--')
    .replace(/&bull;/gi, '•')
    .replace(/&trade;/gi, '™')
    .replace(/&copy;/gi, '©')
    .replace(/&reg;/gi, '®')
    .replace(/[ \t]+/g, ' ')
    .replace(/\n\s*\n\s*\n+/g, '\n\n')
    .trim()
    .substring(0, 5000); // Meta maximum allowed length is 5000 chars
}

/**
 * Normalizes image URLs ensuring proper https protocol.
 */
export function normalizeImageUrl(url?: string | null): string {
  if (!url) return '';
  let clean = url.trim();
  if (clean.startsWith('//')) {
    clean = 'https:' + clean;
  } else if (clean.startsWith('http://')) {
    clean = clean.replace(/^http:\/\//i, 'https://');
  }
  return clean;
}

/**
 * Resolves the base URL for product links according to domain mode.
 */
export function resolveProductDomain(options: ItemMapperOptions): string {
  if (options.productLinkDomain === 'custom' && options.customDomain?.trim()) {
    let domain = options.customDomain.trim();
    if (!domain.startsWith('http://') && !domain.startsWith('https://')) {
      domain = `https://${domain}`;
    }
    return domain.replace(/\/+$/, '');
  }
  if (options.productLinkDomain === 'primary' && options.primaryDomain?.trim()) {
    let domain = options.primaryDomain.trim();
    if (!domain.startsWith('http://') && !domain.startsWith('https://')) {
      domain = `https://${domain}`;
    }
    return domain.replace(/\/+$/, '');
  }
  return `https://${options.shopDomain.replace(/\/+$/, '')}`;
}

/**
 * Maps a Shopify product and its variants to Meta Catalog batch items according to specifications:
 * - 4 Variant Export Modes
 * - Accurate decimal currency prices (e.g. "15.00 USD")
 * - Compare-at vs Price discount rules based on PriceMode
 * - Multiple normalized images via additional_image_urls & additional_image_cdn_urls
 * - Clean HTML descriptions (up to 5000 chars)
 * - Google/FB Product Category taxonomy
 * - Variant attributes (Color, Size, SKU, Barcode/GTIN)
 */
export function mapShopifyProductToMetaItems(
  product: ShopifyProduct,
  options: ItemMapperOptions
): MetaBatchItemRequest[] {
  const baseDomain = resolveProductDomain(options);
  const cleanDescription = cleanHtmlDescription(product.body_html || product.description || product.title);
  const currency = (product.currency || options.currency || 'USD').toUpperCase();

  const productImages = (product.images || [])
    .map(img => (typeof img === 'string' ? normalizeImageUrl(img) : normalizeImageUrl(img?.src)))
    .filter((img): img is string => Boolean(img));

  const defaultImage = normalizeImageUrl(product.image?.src) || productImages[0] || '';

  const formatPrice = (priceStr?: string | number | null): number => {
    if (priceStr === undefined || priceStr === null || priceStr === '') return 0;
    const num = parseFloat(String(priceStr).replace(/[^0-9.]/g, ''));
    return isNaN(num) ? 0 : num;
  };

  const calculatePrices = (variant: ShopifyVariant) => {
    const regularPrice = formatPrice(variant.price);
    const comparePrice = formatPrice(variant.compare_at_price);
    const mode = options.priceMode || 'compare_at_and_price';

    if (mode === 'price_only') {
      return {
        price: `${regularPrice.toFixed(2)} ${currency}`,
        sale_price: undefined,
      };
    }

    if (mode === 'compare_at_only') {
      const p = comparePrice > 0 ? comparePrice : regularPrice;
      return {
        price: `${p.toFixed(2)} ${currency}`,
        sale_price: undefined,
      };
    }

    // Default: 'compare_at_and_price'
    // In Meta & Google commerce specs:
    // If compare_at_price > regularPrice -> 'price' is compare_at_price (original MSRP), 'sale_price' is regularPrice (discount)
    if (comparePrice > regularPrice && regularPrice > 0) {
      return {
        price: `${comparePrice.toFixed(2)} ${currency}`,
        sale_price: `${regularPrice.toFixed(2)} ${currency}`,
      };
    } else {
      return {
        price: `${regularPrice.toFixed(2)} ${currency}`,
        sale_price: undefined,
      };
    }
  };

  const getVariantImages = (variant: ShopifyVariant) => {
    let variantImg: string | undefined = undefined;
    if (variant.image?.src) {
      variantImg = normalizeImageUrl(variant.image.src);
    } else if (variant.image_id && product.images) {
      const match = product.images.find(img => typeof img !== 'string' && img?.id === variant.image_id);
      if (match && typeof match !== 'string' && match.src) {
        variantImg = normalizeImageUrl(match.src);
      }
    }

    // Select best primary image, filtering out any placeholder URLs
    let mainImg = variantImg || defaultImage;
    if ((!mainImg || mainImg.includes('placeholder.com')) && product.variants) {
      for (const v of product.variants) {
        if (v.image?.src && !v.image.src.includes('placeholder.com')) {
          mainImg = normalizeImageUrl(v.image.src);
          break;
        }
      }
    }
    if (mainImg && mainImg.includes('placeholder.com')) {
      mainImg = '';
    }

    let additionalImgs: string[] | undefined = undefined;
    if (options.imageOption === 'all' && productImages.length > 0) {
      additionalImgs = productImages
        .filter(img => img && img !== mainImg && !img.includes('placeholder.com'))
        .slice(0, 19);
    }

    return { mainImg, additionalImgs };
  };

  const resolveAvailability = (variant: ShopifyVariant): 'in stock' | 'out of stock' => {
    if ((variant as any).availableForSale === true || (variant as any).available === true) {
      return 'in stock';
    }
    if (variant.availability === 'in stock') return 'in stock';
    if (variant.availability === 'out of stock') return 'out of stock';
    if (variant.inventory_management === null || variant.inventory_policy === 'continue') {
      return 'in stock';
    }
    return (variant.inventory_quantity ?? 0) > 0 ? 'in stock' : 'out of stock';
  };

  const extractVariantAttributes = (variant: ShopifyVariant) => {
    let color: string | undefined;
    let size: string | undefined;
    let material: string | undefined;
    let pattern: string | undefined;
    let gender: 'male' | 'female' | 'unisex' | undefined;
    let ageGroup: 'adult' | 'all ages' | 'teen' | 'kids' | 'toddler' | 'infant' | undefined;

    // 1. Check selected_options array if present (e.g. from GraphQL or parsed custom_label_2)
    if (variant.selected_options && Array.isArray(variant.selected_options)) {
      for (const opt of variant.selected_options) {
        const name = (opt.name || '').toLowerCase();
        const val = (opt.value || '').trim();
        if (name === 'color' || name === 'colour') color = val;
        else if (name === 'size') size = val;
        else if (name === 'material') material = val;
        else if (name === 'pattern') pattern = val;
        else if (name === 'gender') {
          const lVal = val.toLowerCase();
          if (lVal.includes('fem') || lVal.includes('women')) gender = 'female';
          else if (lVal.includes('men') || lVal.includes('male')) gender = 'male';
          else if (lVal.includes('uni')) gender = 'unisex';
        }
      }
    }

    // 2. Parse variant title if not found (e.g. "Red / XL", "154cm / Wide")
    if ((!color || !size) && variant.title && variant.title !== 'Default Title') {
      const parts = variant.title.split('/').map(s => s.trim());
      for (const p of parts) {
        if (!size && (/^(xs|s|m|l|xl|xxl|2xl|3xl|\d{2,3}(cm)?|us \d+|uk \d+|eu \d+|small|medium|large)$/i.test(p) || /^\d+(\.\d+)?(\s*(cm|mm|in|inch|oz|ml|g|kg))?$/i.test(p))) {
          size = p;
        } else if (!color && /^(red|blue|green|black|white|yellow|orange|purple|pink|grey|gray|brown|navy|gold|silver|beige|cyan|magenta|matte black|carbon|liquid|hydrogen|oxygen|dawn)$/i.test(p)) {
          color = p;
        } else if (!size && parts.length === 1) {
          size = p;
        }
      }
    }

    // 3. Extract from tags or product title if still missing
    const combinedText = `${product.title} ${(product.tags || []).join(' ')}`.toLowerCase();

    // Gender inference
    if (!gender) {
      if (combinedText.includes('women') || combinedText.includes('female') || combinedText.includes('ladies')) {
        gender = 'female';
      } else if (combinedText.includes('men') || combinedText.includes('male') || combinedText.includes('gentlemen')) {
        gender = 'male';
      } else {
        gender = 'unisex';
      }
    }

    // Age Group inference
    if (!ageGroup) {
      if (combinedText.includes('infant') || combinedText.includes('baby')) {
        ageGroup = 'infant';
      } else if (combinedText.includes('toddler')) {
        ageGroup = 'toddler';
      } else if (combinedText.includes('kid') || combinedText.includes('child') || combinedText.includes('youth')) {
        ageGroup = 'kids';
      } else {
        ageGroup = 'adult';
      }
    }

    // Size inference from title/tags if still missing
    if (!size) {
      const sizeMatch = product.title.match(/(\b\d{2,3}\s*cm\b|\b\d{2,3}\b|\b(xs|s|m|l|xl|xxl)\b)/i);
      if (sizeMatch) {
        size = sizeMatch[0];
      }
    }

    // Color inference from combinedText (title + tags + description) if still missing
    if (!color) {
      const colorMatch = combinedText.match(/\b(purple|red|blue|green|black|white|yellow|orange|pink|grey|gray|brown|gold|silver|teal|navy|maroon|olive|cyan|magenta|beige|charcoal|burgundy|violet|lavender|bronze|copper|metallic|matte black|carbon|hydrogen|oxygen|liquid|dawn)\b/i);
      if (colorMatch) {
        color = colorMatch[1].charAt(0).toUpperCase() + colorMatch[1].slice(1);
      }
    }

    // Material inference from combinedText if still missing
    if (!material) {
      const matMatch = combinedText.match(/\b(wood|carbon fiber|carbon|fiberglass|metal|steel|aluminum|plastic|cotton|leather|silk|wool|polyester|nylon|spandex|denim|linen|rubber|canvas|fleece|titanium|ceramic|glass|wax)\b/i);
      if (matMatch) {
        material = matMatch[1].charAt(0).toUpperCase() + matMatch[1].slice(1);
      }
    }

    // Pattern inference from combinedText if still missing
    if (!pattern) {
      const patMatch = combinedText.match(/\b(solid|striped|plaid|checkered|checked|floral|geometric|abstract|polka dot|camo|camouflage|houndstooth|animal print|tie dye|graphic|print)\b/i);
      if (patMatch) {
        pattern = patMatch[1].charAt(0).toUpperCase() + patMatch[1].slice(1);
      }
    }

    return { color, size, material, pattern, gender, ageGroup };
  };

  const defaultCategories = resolveProductCategory(
    product.title,
    product.product_type,
    product.tags
  );
  const resolvedGoogleCategory = options.googleCategory || product.google_product_category || defaultCategories.google_product_category;
  const resolvedFbCategory = product.fb_product_category || defaultCategories.fb_product_category;

  const variants = product.variants && product.variants.length > 0
    ? product.variants
    : [{
        id: product.id,
        product_id: product.id,
        title: product.title,
        price: '0.00',
        sku: '',
        inventory_quantity: 1,
      }];

  const items: MetaBatchItemRequest[] = [];

  switch (options.variantExportMode) {
    case 'first_product_title': {
      // Only first variant with Product Title & Product ID
      const firstVariant = variants[0];
      const { price, sale_price } = calculatePrices(firstVariant);
      const { mainImg, additionalImgs } = getVariantImages(firstVariant);
      const productUrl = `${baseDomain}/products/${product.handle}`;
      const { color, size, material, pattern, gender, ageGroup } = extractVariantAttributes(firstVariant);

      const data: MetaBatchItemPayload = {
        id: String(product.id),
        item_group_id: String(product.id),
        title: product.title,
        description: cleanDescription || product.title,
        availability: resolveAvailability(firstVariant),
        condition: 'new',
        price,
        sale_price,
        link: productUrl,
        image_link: mainImg || undefined,
        image_url: mainImg || undefined,
        additional_image_link: additionalImgs && additionalImgs.length > 0 ? additionalImgs : undefined,
        video: product.video_url || undefined,
        product_type: product.product_type || undefined,
        mobile_link: productUrl,
        rich_text_description: product.body_html || cleanDescription || product.title,
        brand: product.vendor || 'Store',
        google_product_category: resolvedGoogleCategory,
        fb_product_category: resolvedFbCategory,
        color: color || undefined,
        size: size || undefined,
        material: material || undefined,
        pattern: pattern || undefined,
        gender: gender || 'unisex',
        age_group: ageGroup || 'adult',
        sku: firstVariant.sku || undefined,
        mpn: firstVariant.sku || (firstVariant as any).barcode || undefined,
        gtin: (firstVariant as any).barcode || (firstVariant as any).gtin || undefined,
        barcode: (firstVariant as any).barcode || undefined,
        shipping_weight: (firstVariant.weight && firstVariant.weight > 0) ? `${firstVariant.weight} ${firstVariant.weight_unit || 'lb'}` : undefined,
        custom_label_0: product.product_type || undefined,
        custom_label_1: (product.tags || []).slice(0, 3).join(', ') || undefined,
        custom_label_2: size ? `Size: ${size}` : (color ? `Color: ${color}` : undefined),
        custom_label_3: resolveAvailability(firstVariant) === 'in stock' ? 'In Stock' : 'Out of Stock',
        custom_label_4: product.vendor || 'Store',
      };

      items.push({
        method: 'UPDATE',
        retailer_id: String(product.id),
        data,
      });
      break;
    }

    case 'first_variant_title': {
      // Only first variant with Variant Title & Variant ID
      const firstVariant = variants[0];
      const { price, sale_price } = calculatePrices(firstVariant);
      const { mainImg, additionalImgs } = getVariantImages(firstVariant);
      const productUrl = `${baseDomain}/products/${product.handle}?variant=${firstVariant.id}`;
      const title = firstVariant.title && firstVariant.title !== 'Default Title'
        ? `${product.title} - ${firstVariant.title}`
        : product.title;
      const { color, size, material, pattern, gender, ageGroup } = extractVariantAttributes(firstVariant);

      const data: MetaBatchItemPayload = {
        id: String(firstVariant.id),
        item_group_id: String(product.id),
        title,
        description: cleanDescription || product.title,
        availability: resolveAvailability(firstVariant),
        condition: 'new',
        price,
        sale_price,
        link: productUrl,
        image_link: mainImg || undefined,
        image_url: mainImg || undefined,
        additional_image_link: additionalImgs && additionalImgs.length > 0 ? additionalImgs : undefined,
        video: product.video_url || undefined,
        product_type: product.product_type || undefined,
        mobile_link: productUrl,
        rich_text_description: product.body_html || cleanDescription || product.title,
        brand: product.vendor || 'Store',
        google_product_category: resolvedGoogleCategory,
        fb_product_category: resolvedFbCategory,
        color: color || undefined,
        size: size || undefined,
        material: material || undefined,
        pattern: pattern || undefined,
        gender: gender || 'unisex',
        age_group: ageGroup || 'adult',
        sku: firstVariant.sku || undefined,
        mpn: firstVariant.sku || (firstVariant as any).barcode || undefined,
        gtin: (firstVariant as any).barcode || (firstVariant as any).gtin || undefined,
        barcode: (firstVariant as any).barcode || undefined,
        shipping_weight: (firstVariant.weight && firstVariant.weight > 0) ? `${firstVariant.weight} ${firstVariant.weight_unit || 'lb'}` : undefined,
        custom_label_0: product.product_type || undefined,
        custom_label_1: (product.tags || []).slice(0, 3).join(', ') || undefined,
        custom_label_2: size ? `Size: ${size}` : (color ? `Color: ${color}` : undefined),
        custom_label_3: resolveAvailability(firstVariant) === 'in stock' ? 'In Stock' : 'Out of Stock',
        custom_label_4: product.vendor || 'Store',
      };

      items.push({
        method: 'UPDATE',
        retailer_id: String(firstVariant.id),
        data,
      });
      break;
    }

    case 'grouped': {
      // All variants grouped under item_group_id = product.id
      for (const variant of variants) {
        const { price, sale_price } = calculatePrices(variant);
        const { mainImg, additionalImgs } = getVariantImages(variant);
        const productUrl = `${baseDomain}/products/${product.handle}?variant=${variant.id}`;
        const title = variant.title && variant.title !== 'Default Title'
          ? `${product.title} - ${variant.title}`
          : product.title;
        const { color, size, material, pattern, gender, ageGroup } = extractVariantAttributes(variant);

        const data: MetaBatchItemPayload = {
          id: String(variant.id),
          item_group_id: String(product.id),
          title,
          description: cleanDescription || product.title,
          availability: resolveAvailability(variant),
          condition: 'new',
          price,
          sale_price,
          link: productUrl,
          image_link: mainImg || undefined,
          image_url: mainImg || undefined,
          additional_image_link: additionalImgs && additionalImgs.length > 0 ? additionalImgs : undefined,
          video: product.video_url || undefined,
          product_type: product.product_type || undefined,
          mobile_link: productUrl,
          rich_text_description: product.body_html || cleanDescription || product.title,
          brand: product.vendor || 'Store',
          google_product_category: resolvedGoogleCategory,
          fb_product_category: resolvedFbCategory,
          color: color || undefined,
          size: size || undefined,
          material: material || undefined,
          pattern: pattern || undefined,
          gender: gender || 'unisex',
          age_group: ageGroup || 'adult',
          sku: variant.sku || undefined,
          mpn: variant.sku || (variant as any).barcode || undefined,
          gtin: (variant as any).barcode || (variant as any).gtin || undefined,
          barcode: (variant as any).barcode || undefined,
          shipping_weight: (variant.weight && variant.weight > 0) ? `${variant.weight} ${variant.weight_unit || 'lb'}` : undefined,
          custom_label_0: product.product_type || undefined,
          custom_label_1: (product.tags || []).slice(0, 3).join(', ') || undefined,
          custom_label_2: size ? `Size: ${size}` : (color ? `Color: ${color}` : undefined),
          custom_label_3: resolveAvailability(variant) === 'in stock' ? 'In Stock' : 'Out of Stock',
          custom_label_4: product.vendor || 'Store',
        };

        items.push({
          method: 'UPDATE',
          retailer_id: String(variant.id),
          data,
        });
      }
      break;
    }

    case 'all_separate':
    default: {
      // All variants separate with variant ID and item_group_id so Meta can cluster them
      for (const variant of variants) {
        const { price, sale_price } = calculatePrices(variant);
        const { mainImg, additionalImgs } = getVariantImages(variant);
        const productUrl = `${baseDomain}/products/${product.handle}?variant=${variant.id}`;
        const title = variant.title && variant.title !== 'Default Title'
          ? `${product.title} - ${variant.title}`
          : product.title;
        const { color, size, material, pattern, gender, ageGroup } = extractVariantAttributes(variant);

        const data: MetaBatchItemPayload = {
          id: String(variant.id),
          item_group_id: String(product.id),
          title,
          description: cleanDescription || product.title,
          availability: resolveAvailability(variant),
          condition: 'new',
          price,
          sale_price,
          link: productUrl,
          image_link: mainImg || undefined,
          image_url: mainImg || undefined,
          additional_image_link: additionalImgs && additionalImgs.length > 0 ? additionalImgs : undefined,
          video: product.video_url || undefined,
          product_type: product.product_type || undefined,
          mobile_link: productUrl,
          rich_text_description: product.body_html || cleanDescription || product.title,
          brand: product.vendor || 'Store',
          google_product_category: resolvedGoogleCategory,
          fb_product_category: resolvedFbCategory,
          color: color || undefined,
          size: size || undefined,
          material: material || undefined,
          pattern: pattern || undefined,
          gender: gender || 'unisex',
          age_group: ageGroup || 'adult',
          sku: variant.sku || undefined,
          mpn: variant.sku || (variant as any).barcode || undefined,
          gtin: (variant as any).barcode || (variant as any).gtin || undefined,
          barcode: (variant as any).barcode || undefined,
          shipping_weight: (variant.weight && variant.weight > 0) ? `${variant.weight} ${variant.weight_unit || 'lb'}` : undefined,
          custom_label_0: product.product_type || undefined,
          custom_label_1: (product.tags || []).slice(0, 3).join(', ') || undefined,
          custom_label_2: size ? `Size: ${size}` : (color ? `Color: ${color}` : undefined),
          custom_label_3: resolveAvailability(variant) === 'in stock' ? 'In Stock' : 'Out of Stock',
          custom_label_4: product.vendor || 'Store',
        };

        items.push({
          method: 'UPDATE',
          retailer_id: String(variant.id),
          data,
        });
      }
      break;
    }
  }

  return items;
}
