const fs = require('fs')
const path = require('path')
const {
	Filter, orderBy, reduce
} = require('@site-o-mat/query')

const PageFactory = require('./../factories/page.js')
const BlocksQuery = require('./../queries/blocks.js')

/**
 *  Pages - search, filter and find pages
 *
 *  @author Björn Hase <me@herr-hase.wtf>
 *  @license http://opensource.org/licenses/MIT The MIT License
 *  @link https://gitea.node001.net/HerrHase/siteomat-webpack-plugin.git
 *
 */

class Pages {

    /**
     *
     *
     *  @param {string} dirPath
     *
     */
    constructor(dirPath) {

        // constants
        this.FILE_EXTENSION = '.md'
        this.FILE_INDEX = 'index'
        this.DIRECTORY_BLOCKS = '_blocks'

        // default options for find
        this._options = {
            parent: '',
            deep: -1
        }

        this._dirPath = dirPath
        this._results = []
    }

    /**
     *  find pages
     *
     *  @param  {Object} [options={}]
     *  @return {array}
     *
     */
    find(options = {}) {
        this._results = []
        this._count = 0

        options = Object.assign({}, this._options, options)

		if (options.filter) {
			this._filter = new Filter(options.filter)
		}

        this._findFiles(this._dirPath, options)

        //
        if (options.orderBy && options.orderBy.length > 0) {
        	this.results = orderBy(options.orderBy, this._results)
        }

		if (options.limit || options.offset) {
			this._results = reduce(options, this._results)
		}

        return this._results
    }

    /**
     *  find files
     *
     *  @param  {[type]} dirPath                       [description]
     *  @param  {Object} [parameters={}]               [description]
     *  @param  {Object} [options={}]                  [description]
     *  @return {[type]}
     *
     */
    _findFiles(dirPath, options) {

        // getting all files
        const files = fs.readdirSync(dirPath + options.parent, {
            withFileTypes: true
        })

        files.forEach((file) => {

            // skip for file that is not markdown
            if (file.isFile() && path.extname(file.name) !== this.FILE_EXTENSION ) {
                return;
            }

            // skip for file that is index but not root
            if (file.isFile() && file.name === (this.FILE_INDEX + this.FILE_EXTENSION) && options.parent !== '') {
                return;
            }

            // skip for directory that contains partials
            if (file.isDirectory() && file.name === this.DIRECTORY_BLOCKS) {
                return;
            }

            // if directory going deep
            if (file.isDirectory() && (options.deep > 0 || options.deep === -1)) {

                if (options.deep > 0) {
                    options.deep--
                }

                const childrenOptions = Object.assign({}, options, {
                    'parent': options.parent + '/' + file.name
                })

                this._findFiles(dirPath, childrenOptions)
            }

            // get file
            const content = this._getFile(file, dirPath + options.parent)

            // skip if empty
            if (!content) {
                return;
            }

            // check for blocks
            const blocks = this._getBlocks(dirPath + options.parent, file.name)

            // create page object and add to page
            const page = new PageFactory(file, options.parent, content, blocks)

            // check for filters and skip
            if (this._filter && !this._filter.validate(page.get())) {
                return
            }

            this._results.push(page.get())
        })
    }

    /**
     *
     *
     *  @param  {string} dirPath
     *  @return {array}
     *
     */
    _getBlocks(dirPath, filename) {
        const blocksQuery = new BlocksQuery(dirPath, filename)
        return blocksQuery.find()
    }

    /**
     *  get file content
     *
     *  @param  {string} slug
     *  @param  {string} sourcePath
     *  @return {mixed}
     *
     */
    _getFile(file, dirPath) {

        // file
        let result = null

        // path of file, first try with slug
        let filePath = dirPath + '/' + file.name

        if (fs.existsSync(filePath) && file.isFile()) {
            result = fs.readFileSync(filePath, 'utf8')
        } else {
            filePath = dirPath + '/' + file.name + '/' + this.FILE_INDEX + this.FILE_EXTENSION

            if (fs.existsSync(filePath)) {
                result = fs.readFileSync(filePath, 'utf8')
            }
        }

		return result
	}

}

module.exports = Pages
