import { Logger } from '../utils/Logger';

interface ParseConfig {
  selectors: {
    [key: string]: string;
  };
  listSelector?: string;
  attributeMap: {
    [key: string]: {
      selector: string;
      attribute?: string;
      transform?: 'text' | 'number' | 'price' | 'image' | 'url';
    };
  };
}

interface ParsedProduct {
  productId: string;
  name: string;
  price: number;
  originalPrice?: number;
  currency: string;
  images: string[];
  description?: string;
  skuList: Array<{
    skuId: string;
    attributes: Record<string, string>;
    price: number;
    stock: number;
  }>;
  category?: string;
  brand?: string;
  specifications: Record<string, string>;
  source: string;
  url: string;
  parsedAt: string;
}

interface ParseResult {
  success: boolean;
  data?: ParsedProduct | ParsedProduct[];
  error?: string;
  url: string;
  timestamp: string;
  traceId: string;
}

export class DOMParser {
  private logger = new Logger('DOMParser');
  
  private static readonly PLATFORM_CONFIGS: Record<string, ParseConfig> = {
    tiktok: {
      selectors: {
        productName: '[data-e2e="product-title"], .product-title, h1.title',
        price: '[data-e2e="product-price"], .price-current, .product-price',
        originalPrice: '[data-e2e="product-original-price"], .price-original',
        images: '[data-e2e="product-image"] img, .product-image img, .gallery-image img',
        description: '[data-e2e="product-description"], .product-description, .description',
        skuList: '[data-e2e="sku-item"], .sku-item, .variant-item',
      },
      attributeMap: {
        productId: { selector: '[data-product-id]', attribute: 'data-product-id' },
        name: { selector: '[data-e2e="product-title"], .product-title, h1.title', transform: 'text' },
        price: { selector: '[data-e2e="product-price"], .price-current', transform: 'price' },
        currency: { selector: '[data-e2e="product-price"]', transform: 'text' },
        images: { selector: '[data-e2e="product-image"] img', attribute: 'src', transform: 'image' },
      },
    },
    temu: {
      selectors: {
        productName: '.product-title, [data-testid="product-title"], h1',
        price: '.price-current, [data-testid="price"], .sales-price',
        originalPrice: '.price-original, .original-price',
        images: '.product-image img, [data-testid="product-image"] img, .gallery img',
        description: '.product-description, [data-testid="description"]',
        skuList: '.sku-item, [data-testid="sku"], .variant-option',
      },
      attributeMap: {
        productId: { selector: '[data-goods-id]', attribute: 'data-goods-id' },
        name: { selector: '.product-title, [data-testid="product-title"]', transform: 'text' },
        price: { selector: '.price-current, .sales-price', transform: 'price' },
        currency: { selector: '.price-current', transform: 'text' },
        images: { selector: '.product-image img', attribute: 'src', transform: 'image' },
      },
    },
    '1688': {
      selectors: {
        productName: '.d-title, .offer-title, h1.title',
        price: '.price-current, .offer-price, .price-now',
        originalPrice: '.price-original, .offer-original-price',
        images: '.offer-image img, .gallery img, .main-image img',
        description: '.offer-detail, .product-description, .description',
        skuList: '.sku-item, .offer-sku, .prop-item',
      },
      attributeMap: {
        productId: { selector: '[data-offer-id]', attribute: 'data-offer-id' },
        name: { selector: '.d-title, .offer-title', transform: 'text' },
        price: { selector: '.price-current, .offer-price', transform: 'price' },
        currency: { selector: '.price-current', transform: 'text' },
        images: { selector: '.offer-image img', attribute: 'src', transform: 'image' },
      },
    },
  };

  async parseProductPage(
    html: string,
    url: string,
    platform: string,
    traceId: string
  ): Promise<ParseResult> {
    this.logger.info('Starting DOM parsing', { url, platform, traceId });

    try {
      const config = DOMParser.PLATFORM_CONFIGS[platform.toLowerCase()];
      if (!config) {
        throw new Error(`Unsupported platform: ${platform}`);
      }

      const doc = this.parseHTML(html);

      const product = this.extractProductData(doc, config, url, platform);

      this.logger.info('DOM parsing completed', {
        url,
        platform,
        productId: product.productId,
        traceId,
      });

      return {
        success: true,
        data: product,
        url,
        timestamp: new Date().toISOString(),
        traceId,
      };
    } catch (error: any) {
      this.logger.error('DOM parsing failed', {
        url,
        platform,
        error: error.message,
        traceId,
      });

      return {
        success: false,
        error: error.message,
        url,
        timestamp: new Date().toISOString(),
        traceId,
      };
    }
  }

  async parseProductList(
    html: string,
    url: string,
    platform: string,
    traceId: string
  ): Promise<ParseResult> {
    this.logger.info('Starting product list parsing', { url, platform, traceId });

    try {
      const config = DOMParser.PLATFORM_CONFIGS[platform.toLowerCase()];
      if (!config) {
        throw new Error(`Unsupported platform: ${platform}`);
      }

      const doc = this.parseHTML(html);

      const listSelector = config.listSelector || '.product-item, .offer-item, .goods-item';
      const items = doc.querySelectorAll(listSelector);
      const products: ParsedProduct[] = [];

      items.forEach((item: Element, index: number) => {
        try {
          const product = this.extractProductData(item as any, config, url, platform);
          products.push(product);
        } catch (err: any) {
          this.logger.warn(`Failed to parse item ${index}`, { error: err.message });
        }
      });

      this.logger.info('Product list parsing completed', {
        url,
        platform,
        count: products.length,
        traceId,
      });

      return {
        success: true,
        data: products,
        url,
        timestamp: new Date().toISOString(),
        traceId,
      };
    } catch (error: any) {
      this.logger.error('Product list parsing failed', {
        url,
        platform,
        error: error.message,
        traceId,
      });

      return {
        success: false,
        error: error.message,
        url,
        timestamp: new Date().toISOString(),
        traceId,
      };
    }
  }

  private extractProductData(
    doc: any,
    config: ParseConfig,
    url: string,
    platform: string
  ): ParsedProduct {
    const getText = (selector: string): string => {
      const el = doc.querySelector(selector);
      return el ? el.textContent?.trim() || '' : '';
    };

    const getAttribute = (selector: string, attr: string): string => {
      const el = doc.querySelector(selector);
      return el ? el.getAttribute(attr) || '' : '';
    };

    const parsePrice = (text: string): { price: number; currency: string } => {
      const match = text.match(/[$¥€£]\s*([\d,]+\.?\d*)/);
      if (match) {
        const currency = text.match(/[$¥€£]/)?.[0] || 'USD';
        return {
          price: parseFloat(match[1].replace(/,/g, '')),
          currency,
        };
      }
      return { price: 0, currency: 'USD' };
    };

    const productId = getAttribute(config.selectors.productId || '[data-product-id]', 'data-product-id') ||
                      this.extractProductIdFromUrl(url);

    const name = getText(config.selectors.productName);
    const priceText = getText(config.selectors.price);
    const { price, currency } = parsePrice(priceText);

    const originalPriceText = getText(config.selectors.originalPrice);
    const { price: originalPrice } = originalPriceText ? parsePrice(originalPriceText) : { price: undefined };

    const images: string[] = [];
    const imageElements = doc.querySelectorAll(config.selectors.images);
    imageElements.forEach((img: any) => {
      const src = img.getAttribute('src') || img.getAttribute('data-src');
      if (src) {
        images.push(this.normalizeImageUrl(src, url));
      }
    });

    const description = getText(config.selectors.description);

    const skuList: ParsedProduct['skuList'] = [];
    const skuElements = doc.querySelectorAll(config.selectors.skuList);
    skuElements.forEach((sku: any, index: number) => {
      const skuName = sku.textContent?.trim() || `SKU-${index}`;
      const skuPrice = parsePrice(sku.textContent || '').price;
      skuList.push({
        skuId: `${productId}-SKU-${index}`,
        attributes: { name: skuName },
        price: skuPrice || price,
        stock: 0,
      });
    });

    const specifications: Record<string, string> = {};
    const specElements = doc.querySelectorAll('.spec-item, .attribute-item, .property-item');
    specElements.forEach((spec: any) => {
      const key = spec.querySelector('.spec-name, .attr-name')?.textContent?.trim();
      const value = spec.querySelector('.spec-value, .attr-value')?.textContent?.trim();
      if (key && value) {
        specifications[key] = value;
      }
    });

    return {
      productId,
      name,
      price,
      originalPrice,
      currency,
      images: images.slice(0, 10),
      description,
      skuList,
      category: specifications['Category'] || specifications['类目'],
      brand: specifications['Brand'] || specifications['品牌'],
      specifications,
      source: platform,
      url,
      parsedAt: new Date().toISOString(),
    };
  }

  private extractProductIdFromUrl(url: string): string {
    const patterns = [
      /\/product\/(\d+)/i,
      /\/item\/(\d+)/i,
      /\/offer\/(\d+)/i,
      /[?&]id=(\d+)/i,
      /-(\d+)\.html/i,
    ];

    for (const pattern of patterns) {
      const match = url.match(pattern);
      if (match) {
        return match[1];
      }
    }

    return `UNKNOWN-${Date.now()}`;
  }

  private normalizeImageUrl(src: string, baseUrl: string): string {
    if (src.startsWith('http')) {
      return src;
    }
    if (src.startsWith('//')) {
      return `https:${src}`;
    }
    if (src.startsWith('/')) {
      const url = new URL(baseUrl);
      return `${url.protocol}//${url.host}${src}`;
    }
    return src;
  }

  private parseHTML(html: string): Document {
    const parser = new (globalThis as any).DOMParser();
    return parser.parseFromString(html, 'text/html');
  }
}
