const path = require('path');
const Promise = require('bluebird');
const fs = require('fs-extra');
const log = require('fancy-log');
const File = require('./file');
const actions = require('./actions');
const { URL } = require('url');
const { resolve, readFile, isCleanUrl, ENGINE } = require('./resolve');
const { isObject, isString } = require('./lib/util');

const pkg  = require(resolve('package.json'));
const frontmatter = require('front-matter');

module.exports = exports = class Page extends File {

  constructor (filepath) {
    super(filepath);

    this.serializable.push(
      'fullurl',
      'engine',
      'source',
      'meta',
      'images',
      'titlecard',
      'tweets',
      'dateCreated',
      'dateModified',
      'classes',
      'flags',
    );

    this.engine = ENGINE[this.type] || ENGINE.COPY;
  }

  _out () {
    var isIndexPage = (this.name === 'index');
    var isClean = isCleanUrl(this.ext);

    if (isClean && isIndexPage) {
      this.out     = path.join(this.base, 'index.html');
      this.json    = path.join(this.base, 'index.json');
      this.url     = this.dir;
    } else if (isClean) {
      this.out     = path.join(this.base, this.name, 'index.html');
      this.json    = path.join(this.base, this.name + '.json');
      this.url     = path.join(this.dir, this.name);
    } else if (isIndexPage) {
      this.out     = path.join(this.base, 'index.html');
      this.json    = path.join(this.base, this.name + '.json');
      this.url     = this.dir;
    } else {
      this.out     = path.join(this.base, this.basename);
      this.json    = path.join(this.base, this.basename + '.json');
      this.url     = path.join(this.dir, this.basename);
    }

    const url = new URL(pkg.siteInfo.siteUrl);
    url.pathname = this.url;
    this.fullurl = url.href;
  }

  async load (PublicFiles) {
    const [ raw, { ctime, mtime } ] = await Promise.all([
      readFile(this.input).catch(() => null),
      fs.stat(this.input).catch(() => ({})),
    ]);

    // empty file
    if (!raw || !ctime) {
      log.error('Could not load page: ' + this.filepath);
      return false;
    }

    try {
      var { attributes: meta, body } = frontmatter(raw.toString('utf8'));
    } catch (e) {
      log.error('Error while parsing frontmatter for ' + this.filepath, e);
      return false;
    }

    this.source = body;
    this.meta = meta;
    this.dateCreated = meta.date && new Date(meta.date) || ctime;
    this.dateModified = mtime;

    this._parse(PublicFiles);

    return this;
  }

  _parse (PublicFiles) {
    const { titlecard, webready } = PublicFiles.for(this.dir);

    this.ignore = this.meta.ignore;
    this.images = webready;
    this.titlecard = titlecard;
    if (this.meta.tweets && isString(this.meta.tweets)) this.meta.tweets = this.meta.tweets.split(/\s/);
    this.tweets = (this.meta.tweets || []).map(parseTweetId);

    this.classes = Array.from(new Set(this.meta.classes || []));
    this.flags = this.classes.reduce((res, item) => {
      var camelCased = item.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
      res[camelCased] = true;
      return res;
    }, {});

  }

  tasks () {
    if (!isObject(this.tweets)) return [];

    return Object.values(this.tweets)
      .map((t) => t.media)
      .flat()
      .map((m) => ({ ...m, action: actions.fetch, output: m.output }));
  }

};

/* Utility Functions **************************************************/

const tweeturl = /https?:\/\/twitter\.com\/(?:#!\/)?(?:\w+)\/status(?:es)?\/(\d+)/i;
const tweetidcheck = /^\d+$/;
function parseTweetId (tweetid) {
  // we can't trust an id that isn't a string
  if (typeof tweetid !== 'string') return false;

  const match = tweetid.match(tweeturl);
  if (match) return match[1];
  if (tweetid.match(tweetidcheck)) return tweetid;
  return false;
}