/**
 * @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md.
 */

'use strict';

const { styleText } = require( 'util' );
const path = require( 'path' );
const compileSass = require( './tasks/compile-sass' );
const runWebpack = require( './tasks/run-webpack' );
const copyAssets = require( './tasks/copy-assets' );
const getMainConfig = require( './tasks/get-main-config' );
const createSymLinks = require( './tasks/create-sym-links' );
const buildDocumentation = require( './tasks/build-documentation' );
const getProjectConfig = require( './tasks/get-project-config' );
const watcher = require( './tasks/watcher' );
const validateHtml = require( './tasks/validate-html-w3c' );
const { version } = require( '../package.json' );

module.exports = {
	/**
	 * Builds documentation for a single project.
	 * Intended to use within project's task runner or along other build scripts.
	 *
	 * @param {Options} [options={}]
	 * @returns {Promise}
	 */
	async buildSingleProject( options = {} ) {
		try {
			const config = await getProjectConfig( process.cwd(), options );

			options.mainConfig = {
				...config,
				projects: [ '.' ],
				isSingleProject: true
			};

			await buildAndWatch( options );
		} catch ( err ) {
			console.error( styleText( 'redBright', `Building documentation failed: ${ err.stack }` ) );
			process.exitCode = 1;

			throw err;
		}
	},

	/**
	 * Builds documentation for multiple projects at once.
	 *
	 * @param {Options} [options={}]
	 * @returns {Promise}
	 */
	async buildMultiProjects( options = {} ) {
		try {
			await buildAndWatch( options );
		} catch ( err ) {
			console.error( styleText( 'redBright', `Building documentation failed: ${ err.stack }` ) );
			process.exitCode = 1;

			throw err;
		}
	}
};

/**
 * @param {Options} options
 * @returns {Promise}
 */
async function buildAndWatch( options ) {
	const timer = process.hrtime();
	const outputDir = path.join( process.cwd(), 'build', 'docs' );

	const hexoManager = await buildDocumentation( options );

	if ( !options.skipThemes ) {
		await buildThemes( outputDir, options );
	}

	if ( options.validateW3C ) {
		await validateHtml( outputDir, options );
	}

	if ( options.createSymLinks !== false ) {
		const rootPath = process.cwd();

		await createSymLinks( {
			rootPath,
			mainConfig: options.mainConfig || getMainConfig( rootPath ),
			isSingleProject: options.mainConfig ? options.mainConfig.isSingleProject : false
		} );
	}

	const [ time ] = process.hrtime( timer );

	console.log( styleText( 'greenBright', `Building documentation complete in ${ Math.floor( time / 60 ) }m ${ time % 60 }s.` ) );

	if ( options.watch ) {
		return watcher( hexoManager );
	}

	return null;
}

async function buildThemes( outputDir, options ) {
	const themesDir = path.join( __dirname, '../themes/umberto' );
	const sourceDir = path.join( themesDir, 'src' );
	const outputAssetsPath = path.join( outputDir, 'assets', version );
	const layoutThemes = [ 'umberto', 'gloria' ];

	for ( const theme of layoutThemes ) {
		await runWebpack(
			path.join( sourceDir, theme, 'js/app.js' ),
			path.join( outputAssetsPath, theme, 'scripts' ),
			{
				minify: !options.dev,
				umbertoDir: themesDir,
				version
			}
		);

		await copyAssets(
			path.join( themesDir, 'source', theme ),
			path.join( outputAssetsPath, theme )
		);

		await compileSass(
			path.join( sourceDir, theme, 'css/styles.scss' ),
			path.join( outputAssetsPath, theme, 'css/styles.css' )
		);
	}
}

/**
 * @typedef {Object} Options
 * @property {boolean} [skipApi=false] Skips rendering API docs.
 * @property {boolean} [skipValidation=false] Skips validating links.
 * @property {boolean} [skipLiveSnippets=false] Skips building live code snippets.
 * @property {Object} [snippetOptions={}] Additional options passed to snippetAdapter.
 * @property {boolean} [dev=false] Skip JS minification, don't clear build directory when rebuilding docs, reuse unchanged files.
 * @property {boolean} [verbose=false] Adds more information to console during documentation building.
 * @property {boolean} [createSymLinks=true] Add symbolic links with 'latest' to output folder.
 * @property {boolean} [watch=false] Run Umberto with watch mode, which track changes in dm files and rebuild docs with it.
 * @property {boolean} [validateW3C=false] Use vnu java validator to check every single output page for html syntax errors.
 */
