var fs = require('fs');
var path = require('path');
var process = require('process');

module.exports = function(grunt) {
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-connect');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-replace');
	grunt.loadNpmTasks('@lodder/grunt-postcss');

	const sass = require('sass');
	

	require('load-grunt-tasks')(grunt); //sass

	grunt.registerTask('default', [
		'build'
	]);


	grunt.registerTask('build', [
		'clean:library',

		'shell:buildjs',

		'copy:scss',
		'copy:scss_plugins',
		'sass:build',
		'postcss:prefix',
		'postcss:min',
		'replace:css_post',
		'replace:scss_plugin_paths'
	]);

	grunt.registerTask('serve', [
		'build',
		'builddocs',
		'connect',
		'check_doc_links',
		'watch'
	])

	grunt.registerTask('builddocs',[
		'clean:builddocs',
		'shell:builddocs',
		'shell:rollupdocs',
		'replace:builddocs',
		'sass:builddocs',
		'postcss:builddocs',
	]);



	/**
	 * Check generated docs for broken links
	 * https://www.npmjs.com/package/broken-link-checker
	 */
	grunt.registerTask('check_doc_links','',function(){
		var done = this.async();
		const {SiteChecker} = require('broken-link-checker');
		const options = {
			excludeExternalLinks: true,
			cacheMaxAge:60,
		};

		var urls_checked	= 0;
		var links_checked	= 0;
		var failures		= 0;


		const handlers = {
			error:function(error){
				failures++;
				console.log('error',error);
			},
			page:function(error, page_url, customData){
				if( error ){
					failures++;
					console.log('error!',page_url);
				}

				urls_checked++;
			},
			junk:function( result, data ){

				links_checked++;
				if( result.broken ){
					failures++;
					console.log('broken junk found',result);
				}
			},
			link:function(link){
				if( link.broken ){
					failures++;
					console.log('broken link',link);
				}
			},
			end:function(){
				console.log('urls checked',urls_checked);
				console.log('links checked',links_checked);
				console.log('failures',failures);

				done(failures==0);
			}
		};

		const checker = new SiteChecker(options,handlers)
		checker.enqueue('http://localhost:8000/', {});
	});


	// build tom-select.custom.js
	var plugin_arg			= grunt.option('plugins');
	var custom_file			= path.resolve( process.cwd(),'./src/tom-select.custom.ts');
	var custom_content		= ['/* this file is generated by grunt when calling `npm run build -- --plugins=<plugins> */','import TomSelect from "./tom-select";'];

	if( fs.existsSync(custom_file) ){
		fs.unlink(custom_file,err => {
			if (err) {
				console.error(err)
			}
		});
	}

	if( plugin_arg ){
		var plugin_args	= plugin_arg.split(/\s*,\s*/);

		plugin_args.map((plugin_name) => {
			custom_content.push(`import ${plugin_name} from './plugins/${plugin_name}/plugin.js';`);
		});
		plugin_args.map((plugin_name) => {
			custom_content.push(`TomSelect.define('${plugin_name}', ${plugin_name});`);
		});
		custom_content.push('export default TomSelect;');

		fs.writeFile(custom_file, custom_content.join("\n"),err => {
			if (err) {
				console.error(err)
			}
		});
	}



	// find all plugin scss files
	var scss_plugin_files	= [];
	var matched_files = grunt.file.expand(['src/plugins/*/plugin.scss']);
	for (var i = 0, n = matched_files.length; i < n; i++) {
		var plugin_name = matched_files[i].match(/src\/plugins\/(.+?)\//)[1];
		scss_plugin_files.push({src: matched_files[i], dest: 'dist/scss/plugins/' + plugin_name + '.scss'});
	}



	// bootstrap browserlist https://github.com/twbs/bootstrap/blob/main/.browserslistrc
	var autoprefixer = require('autoprefixer')();


	var version_replace_options = {
		prefix: '//@@',
		variables: {
			'version': '<%= pkg.version %>',
		}
	};

	var scss_plugin_path_replace_options = {
		patterns: [{
			match: /\.\.\/plugins\/(.+?)\/plugin\.scss/g,
			replacement: './plugins/$1.scss'
		}],
		usePrefix: false
	};


	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),

		// delete old files
		clean: {
			library: ['dist/*'],
			builddocs: ['build-docs/*']
		},

		// copy scss files to build folder
		copy: {
			scss:{
				files: [{
					'dist/scss/tom-select.scss': ['src/scss/tom-select.scss'],
					'dist/scss/tom-select.default.scss': ['src/scss/tom-select.default.scss'],
					'dist/scss/tom-select.bootstrap4.scss': ['src/scss/tom-select.bootstrap4.scss'],
					'dist/scss/tom-select.bootstrap5.scss': ['src/scss/tom-select.bootstrap5.scss'],
					'dist/scss/_dropdown.scss': ['src/scss/_dropdown.scss'],
					'dist/scss/_items.scss': ['src/scss/_items.scss'],
				}]
			},
			scss_plugins:{
				files: scss_plugin_files
			},
		},

		// replace //@@version with current package version
		replace: {
			// add version to css & scss headers
			css_post: {
				options: version_replace_options,
				files: [
					{expand: true, flatten: false, src: ['dist/css/*.css'], dest: ''},
					{expand: true, flatten: false, src: ['dist/scss/*.scss'], dest: ''},
				]
			},
			builddocs:{
				options: version_replace_options,
				files:[
					{src:['build-docs/js/index.bundle.js'],dest:'build-docs/js/index.bundle.js'},
					{src:['build-docs/index.html'],dest:'build-docs/index.html'}
				]
			},
			scss_plugin_paths: {
				options: scss_plugin_path_replace_options,
				files: [{expand: true, flatten: false, src: ['dist/scss/tom-select.scss'], dest: ''}]
			},
		},


		// compile css from scss
		sass: {
			options:{
				implementation: sass,
				style:'expanded',
			},
			build: {
				files: [{
					'dist/css/tom-select.css': ['src/scss/tom-select.scss'],
					'dist/css/tom-select.default.css': ['src/scss/tom-select.default.scss'],
					'dist/css/tom-select.bootstrap4.css': ['src/scss/-tom-select.bootstrap4.scss'],
					'dist/css/tom-select.bootstrap5.css': ['src/scss/-tom-select.bootstrap5.scss'],
				}]
			},
			builddocs: {
				files: [{
					expand: true,
					flatten: true,
					ext: '.css',
					src: ['doc_src/css/*.scss'],
					dest: 'build-docs/css'
				}],
			}
		},

		// autoprefix && cssnanao
		postcss: {
			prefix: {
				options:{
					map: {
						inline: false, // save all sourcemaps as separate files...
					},
					processors: [
						//require('pixrem')(), // add fallbacks for rem units
						autoprefixer,
					]
				},
				files: [{expand: true, flatten: false, src: ['dist/css/*.css'], dest: ''}],
			},
			min: {
				options: {
					map: {
						inline: false, // save all sourcemaps as separate files...
					},
					processors: [
						require('cssnano')() // minify the result
					]
				},
				files: [{
					'dist/css/tom-select.min.css': ['dist/css/tom-select.css'],
					'dist/css/tom-select.default.min.css': ['dist/css/tom-select.default.css'],
					'dist/css/tom-select.bootstrap4.min.css': ['dist/css/tom-select.bootstrap4.css'],
					'dist/css/tom-select.bootstrap5.min.css': ['dist/css/tom-select.bootstrap5.css'],
				}]
			},
			builddocs:{
				options:{
					map: {
						inline: false, // save all sourcemaps as separate files...
					},
					processors: [
						autoprefixer,
						require('cssnano')() // minify the result
					]
				},
				files: [{
					expand: true,
					flatten: true,
					src: ['build-docs/css/*.css'],
					dest: 'build-docs/css'
				}],
			},
		},

		// run server at http://localhost:8000 to view documentation and run examples
		connect: {
			server:{
				options: {
					base: 'build-docs',
				}
			}
		},

		// generate /build-docs
		shell: {
			builddocs: {
				command: 'npx @11ty/eleventy --config=.config/eleventy.js',
			},
			rollupdocs: {
				command: 'npx rollup -c .config/rollup.docs.mjs',
			},
			buildjs: {
				command: 'npm run build:js',
			},
		},

		watch: {
			// changes to files in /doc_src: rebuild all of documentation
			docs:{
				files:[
					'doc_src/**',
				],
				tasks:[
					'builddocs',
					'check_doc_links',
				]
			},
			// changes to files in /src: rebuild library and copy to docs
			src:{
				files: [
					'src/**',
				],
				tasks: [
					'build',
					'shell:builddocs',
				]
			}
		}
	});
};