const BaseExtractor = require('./base');

class GenericExtractor extends BaseExtractor {
  constructor() {
    super();
    this.patterns = [/.+/];
  }

  getExtractCode() {
    return String.raw`
      (function() {
        var casinos = [];
        var seenNames = {};
        var maxResults = 25;

        function safeText(el, maxLen) {
          if (!el) return '';
          var t = el.textContent.trim().replace(/\s+/g, ' ');
          return maxLen && t.length > maxLen ? t.slice(0, maxLen) : t;
        }

        function cleanName(raw) {
          if (!raw || typeof raw !== 'string') return '';
          return raw
            .replace(/\s*logo\s*$/i, '')
            .replace(/[Cc]asino\s*$/, '')
            .replace(/\s+/g, ' ')
            .trim();
        }

        function isValidBrand(name) {
          if (!name || name.length < 3 || name.length > 60) return false;
          if (!/[a-zA-Z]/.test(name[0])) return false;
          var letterCount = (name.match(/[a-zA-Z]/g) || []).length;
          if (letterCount / name.length < 0.55) return false;

          var junkPatterns = [
            'menu', 'nav', 'home', 'contact', 'about', 'terms', 'privacy',
            'login', 'signup', 'register', 'account', 'support', 'help',
            'subscribe', 'newsletter', 'best casinos', 'top casinos', 'online casinos',
            'real money', 'free spin', 'welcome bonus', 'no deposit',
            'crypto casino', 'bitcoin', 'payout speed', 'visit site',
            'get bonus', 'claim offer', 'read review', 'dmca', 'gambleaware',
            'play now', 'our guide', 'editorial', 'sitemap'
          ];
          var lower = name.toLowerCase();
          for (var i = 0; i < junkPatterns.length; i++) {
            if (lower.includes(junkPatterns[i])) return false;
          }
          return true;
        }

        function isExcludedNode(el) {
          if (!el) return true;
          var tag = el.tagName.toLowerCase();
          if (['nav', 'footer', 'header'].indexOf(tag) >= 0) return true;
          var role = (el.getAttribute('role') || '').toLowerCase();
          if (['navigation', 'contentinfo', 'banner'].indexOf(role) >= 0) return true;
          var cls = (' ' + (el.className || '') + ' ').toLowerCase();
          var excludedClasses = [
            'nav-', 'navbar', 'footer', 'header', 'cookie', 'modal',
            'overlay', 'banner', 'sidebar', 'social-', 'share-',
            'author-', 'bio-', 'skip-link', 'breadcrumb'
          ];
          for (var i = 0; i < excludedClasses.length; i++) {
            if (cls.indexOf(excludedClasses[i]) >= 0) return true;
          }
          return false;
        }

        function getExternalLink(cardNode) {
          var pageHost = location.hostname.replace('www.', '');
          var links = cardNode.querySelectorAll('a[href]');
          var bestMatch = null;
          for (var a = 0; a < links.length; a++) {
            try {
              var resolvedUrl = new URL(links[a].href, document.baseURI);
              var lh = resolvedUrl.hostname.replace('www.', '');
              if (!lh || lh === pageHost) continue;
              if (lh.indexOf('google') >= 0 || lh.indexOf('facebook') >= 0 || lh.indexOf('twitter') >= 0 || lh.indexOf('instagram') >= 0) continue;
              var atxt = links[a].textContent.trim().toLowerCase();
              if (atxt.indexOf('visit') >= 0 || atxt.indexOf('bonus') >= 0 || atxt.indexOf('play') >= 0 || atxt.indexOf('claim') >= 0) {
                return resolvedUrl.origin;
              }
              if (!bestMatch) bestMatch = resolvedUrl.origin;
            } catch(e) {}
          }
          return bestMatch || '';
        }

        function tryExtractFromCard(card) {
          if (isExcludedNode(card)) return null;
          if (casinos.length >= maxResults) return null;

          var imgs = card.querySelectorAll('img');
          var brandName = '';

          for (var i = 0; i < imgs.length; i++) {
            var alt = (imgs[i].getAttribute('alt') || '').trim();
            if (!alt) continue;
            var cleaned = cleanName(alt);
            if (isValidBrand(cleaned)) {
              brandName = cleaned;
              break;
            }
          }

          if (!brandName || seenNames[brandName.toLowerCase()]) return null;

          var extLink = getExternalLink(card);
          if (!extLink) return null;

          var bonusText = '';
          var allEls = card.querySelectorAll('span, p, div');
          for (var j = 0; j < allEls.length && !bonusText; j++) {
            var t = safeText(allEls[j], 200);
            if (/\d+\s*(free spins|spins)/i.test(t) || /[£€$]\d+/.test(t)) {
              bonusText = t.replace(/welcomed?\s*bonus/gi, '').trim();
            }
          }

          seenNames[brandName.toLowerCase()] = true;
          casinos.push({
            position: casinos.length + 1,
            name: brandName,
            link: extLink,
            bonus: bonusText
          });
        }

        var cardSelectors = [
          '.review-card', '.casino-item', '.casino-box', '.card-listing',
          '[class*="ranking"]', '[class*="columns-wrapper"]',
          '[class*="mainProduct"]', '[class*="topContainer"]'
        ].join(', ');

        var candidateCards = document.querySelectorAll(cardSelectors);

        if (candidateCards.length === 0) {
          var sectionDivs = document.querySelectorAll('.section-body, .content, main > div, article');
          for (var s = 0; s < sectionDivs.length; s++) {
            var childDivs = sectionDivs[s].querySelectorAll(':scope > div');
            for (var c = 0; c < childDivs.length; c++) {
              candidateCards = Array.from(candidateCards || []);
              candidateCards.push(childDivs[c]);
            }
          }
        }

        if (candidateCards.length === 0) {
          var allDivs = document.querySelectorAll('div[class]');
          candidateCards = allDivs;
        }

        for (var ci = 0; ci < candidateCards.length && casinos.length < maxResults; ci++) {
          var card = candidateCards[ci];
          if (!card.querySelector('img')) continue;
          if (!card.querySelectorAll('a[href]').length) continue;
          tryExtractFromCard(card);
        }

        return casinos.slice(0, maxResults);
      })()
    `;
  }
}

module.exports = GenericExtractor;
