const path = require('path');
const fs = require('fs');
const BaseExtractor = require('../extractors/base');

class ExtractorManager {
  constructor() {
    this._instance = null;
    this._extractors = [];
    this._initialized = false;
  }

  static _singleton = null;
  static getInstance() {
    if (!ExtractorManager._singleton) {
      ExtractorManager._singleton = new ExtractorManager();
      ExtractorManager._singleton._discover();
    }
    return ExtractorManager._singleton;
  }

  _discover() {
    if (this._initialized) return;
    this._initialized = true;

    const extractorsDir = path.join(__dirname, '..', 'extractors');
    const files = fs.readdirSync(extractorsDir).filter(f => f.endsWith('.js') && f !== 'base.js' && f !== '../services/extractorManager.js');

    for (const file of files) {
      try {
        const ExportedClass = require(path.join(extractorsDir, file));
        const instance = new ExportedClass();
        if (instance instanceof BaseExtractor) {
          this._extractors.push({
            module: file,
            class: ExportedClass,
            instance: instance,
            isGeneric: file === 'generic.js'
          });
        }
      } catch (e) {
        console.warn(`  Failed to load extractor ${file}: ${e.message}`);
      }
    }

    this._extractors.sort((a, b) => {
      if (a.isGeneric && !b.isGeneric) return 1;
      if (!a.isGeneric && b.isGeneric) return -1;
      return b.instance.patterns.length - a.instance.patterns.length;
    });
  }

  getExtractor(url) {
    for (const ext of this._extractors) {
      if (ext.isGeneric) continue;
      if (ext.instance.canHandle(url)) {
        return ext.class;
      }
    }
    const generic = this._extractors.find(e => e.isGeneric);
    if (generic) return generic.class;

    const baseGeneric = new BaseExtractor();
    baseGeneric.patterns = [/.+/];
    return baseGeneric.constructor;
  }

  async run(page, ExtractorClass) {
      var instance = new ExtractorClass();
    try {
      const jsCode = instance.getExtractCode();
      const results = await page.evaluate(jsCode);
      if (!Array.isArray(results)) return [];

      return results.map((item, idx) => ({
        position: idx + 1,
        name: (item.name || '').toString().trim(),
        link: (item.link || '').toString().trim(),
        bonus: (item.bonus || '').toString().trim()
      })).filter(c => c.name.length >= 2);
    } catch (e) {
      console.warn(`  Extractor ${ExtractorClass.name} failed: ${e.message}`);
      return [];
    }
  }
}

module.exports = ExtractorManager;
