const gulp = require('gulp');

/*
 *  Import gulp tasks from package. Configure as described in
 *  this file.
 *
 *  If needed, these tasks can be replaced by custom ones.
 */
const {
    buildCSS,
    lintCSS,
    buildJS,
    purgeCSS,
    watch,
    injectFiles,
} = require('@nimius/gulp-tasks');

/*
 *  CSS Build task. Bundles stylesheets after pre and
 *  post processing via sass and postcss.
 */
gulp.task('build:css', () => buildCSS({
    /*
     *  Path glob for all stylesheet entry files in this
     *  project. Supports defining one or many stylesheets.
     *  Should be relative to the project root.
     */
    src: './Resources/Private/Sass/*.scss',

    /*
     *  Path where the output bundle(s) will be placed.
     *  Should be relative to the target site package.
     *  Should NOT begin with a leading slash.
     */
    dist: './Resources/Public/Stylesheets',

    /*
     *  Options to be passed on to sass pre-processor.
     *  See https://github.com/sass/node-sass#usage for
     *  available settings.
     */
    sassOptions: {
        includePaths: '../node_modules',
    },
}));

/*
 *  CSS Lint task. Runs stylelint on specified source files.
 *  See stylelint.config.js for configuration.
 */
gulp.task('lint:css', () => lintCSS({
    // Path glob for all sass files in this site package.
    src: './Resources/Private/Sass/**/*.scss',

    /*
     *  Options to be passed to gulp-stylelint. See
     *  Check https://www.npmjs.com/package/gulp-stylelint for
     *  available settings.
     */
    lintOptions: {
        failAfterError: false,
        reporters: [
            { formatter: 'string', console: true },
        ],
    },
}));

/*
 *  Extractor to be used by purgecss.
 *  More info here: https://www.purgecss.com/extractors
 */
class TailwindExtractor {
    static extract(content) {
        return content.match(/[A-z0-9-:/]+/g) || [];
    }
}

/*
 *  CSS Purge task. Removes all unneeded classes from the
 *  bundled stylesheets.
 */
gulp.task('css:purge', () => purgeCSS({
    // Path glob for all stylesheets which should be purged.
    src: './Resources/Public/Stylesheets/*.css',

    // Path where purged stylesheets are placed (same directory as src).
    dist: './Resources/Public/Stylesheets',

    /*
     *  Options to be passed to purgecss.
     *  More info here: https://www.npmjs.com/package/gulp-purgecss
     */
    purgeOptions: {
        content: [
            /*
             *  Specify the files (glob paths) to scan for class names.
             *  If a class name is found in any of these files, purge will
             *  not delete style definitions for this class.
             */
            '../../Plugins/Newland.AssetsNeos/Styles/vendor/**/*.scss',
            '../../Plugins/Newland.AssetsNeos/Styles/components-map/*.scss',
            '../../Application/Newland.NeosFiltering/**/*.html',
            '../../Application/Newland.NeosFiltering/**/*.fusion',
            './Resources/Private/Sass/vendor/**/*.scss',
            './Resources/Private/Sass/toubiz/**/*.scss',
            './Resources/Private/Sass/overrides/**/*.scss',
            './Resources/**/!(CriticalCSS|TportalCriticalCSS).html',
            './Resources/**/*.fusion',
            './Configuration/**/*.yaml',
            './Resources/Private/**/*.js',
            './Resources/Private/**/*.vue',
            '../../Plugins/**/*.html',
            '../../Plugins/**/*.yaml',
            '../../Plugins/**/*.fusion',
            '../../Plugins/**/!(qrcode).vue',
        ],
        extractors: [
            {
                extractor: TailwindExtractor,

                /*
                 *  Specify the file extensions to include when
                 *  scanning for class names.
                 */
                extensions: [ 'js', 'html', 'scss', 'md', 'yaml', 'fusion', 'vue' ],
            },
        ],
    },
}));

/*
 *  JS Build task. Is handled by webpack. See
 *  webpack.config.js for configuration. Gulp only starts
 *  webpack and is informed about its comlpetion via the
 *  'done' callback (is passed on to the task).
 */
gulp.task('build:js', done => buildJS(done));

/*
 *  Watch task. Map glob paths of source files to tasks which
 *  should be executed after the files have changed.
 */
gulp.task('watch', done => watch(done, {
    /*
     *  Option watchMap is an Array of Objects with properties
     *  paths (string, path glob) and tasks (array of strings,
     *  names of the tasks to execute). Tasks will be executed
     *  in parallel.
     */
    watchMap: [
        {
            paths: './Resources/Private/Sass/**/*.scss',
            tasks: [
                'lint:css',
                'build:css',
                'files:inject',
            ],
        },
        {
            paths: './Resources/Private/Javascript/**/*.js',
            tasks: [
                'build:js',
            ],
        },
    ],
}));

/*
 *  File injection task. Takes the source of one file and injects its contents
 *  into another.
 */
gulp.task('files:inject', done => injectFiles(done, {
    /*
     *  fileMap is an array of objects with required properties src and dist
     *  and optionally, a pipe function to modify the source before inserting.
     */
    fileMap: [
        {
            src: './Resources/Public/Stylesheets/critical.css',
            dist: './Resources/Private/Templates/Page/Partials/CriticalCSS.html',
            pipe: src => `<style>${src}</style>`,
        },
        {
            src: './Resources/Public/Stylesheets/tportal-critical.css',
            dist: './Resources/Private/Templates/Page/Partials/TportalCriticalCSS.html',
            pipe: src => `<style>${src}</style>`,
        },
    ],
}));

// Development build task sequence.
gulp.task('build:development', gulp.parallel(
    'build:css',
    'build:js',
));

// Production build task sequence.
gulp.task('build:production', gulp.series(
    'build:css',
    gulp.parallel(
        'css:purge',
        'build:js',
    ),
    'files:inject',
));

// Development sequence. Build assets and watch source files.
gulp.task('dev', gulp.parallel(
    'build:development',
    'watch',
));

// Build task defaults to production build
gulp.task('build', gulp.task('build:production'));

// Default task assignment.
gulp.task('default', gulp.task('build'));
