const fetch = require('node-fetch');
const ProxyAgent = require('proxy-agent');
const { merge } = require('lodash');

const { SCRAPER_HEADERS, SCRAPER_PROXY_URL } = require('../../config');
const kue = require('../kue');
const { version } = require('../../package.json');

// Load the scraper with the rules.
const metascraper = require('metascraper').load([
  require('metascraper-title')(),
  require('metascraper-description')(),
  require('metascraper-image')(),
  require('metascraper-author')(),
  require('metascraper-date')(),
  require('./rules/modified')(),
  require('./rules/section')(),
]);

let customHeaders = {};
try {
  customHeaders = JSON.parse(SCRAPER_HEADERS);
} catch (err) {
  console.error('Cannot parse TALK_SCRAPER_HEADERS');
  throw err;
}

// Parse the headers to be added to the scraper.
const headers = merge(
  {
    'User-Agent': `Coral-Talk/${version}`,
  },
  customHeaders
);

// Add proxy configuration if exists.
const agent = SCRAPER_PROXY_URL ? new ProxyAgent(SCRAPER_PROXY_URL) : null;

/**
 * Exposes a service object to allow operations to execute against the scraper.
 * @type {Object}
 */
const scraper = {
  /**
   * Create the new Task kue singleton.
   */
  task: new kue.Task({
    name: 'scraper',
  }),

  /**
   * Creates a new scraper job and scrapes the url when it gets processed.
   */
  async create(ctx, id) {
    ctx.log.info({ assetID: id }, 'Creating job');

    const job = await scraper.task.create({
      title: `Scrape for asset ${id}`,
      id: ctx.id,
      asset_id: id,
    });

    ctx.log.info({ jobID: job.id, assetID: id }, 'Created job');

    return job;
  },

  /**
   * Scrapes the given asset for metadata.
   */
  async scrape(url) {
    const res = await fetch(url, {
      headers,
      agent,
    });
    const html = await res.text();

    if (!res.ok) {
      let err = new Error(res.statusText);
      err.response = res;
      throw err;
    }

    // Get the metadata from the scraped html.
    const meta = await metascraper({
      html,
      url,
    });

    return {
      title: meta.title || '',
      description: meta.description || '',
      image: meta.image ? meta.image : '',
      author: meta.author || '',
      publication_date: meta.date || '',
      modified_date: meta.modified || '',
      section: meta.section || '',
    };
  },
};

module.exports = scraper;
