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

'use strict';

const fs = require( 'fs' );
const { globSync } = require( 'glob' );
const upath = require( 'upath' );
const { URL } = require( 'url' );
const { SitemapStream, streamToPromise } = require( 'sitemap' );

/**
 * Creates a sitemap.xml file and saves it to build directory.
 *
 * @param {Object} options
 * @param {String} options.fileName
 * @param {String} options.projectSlug
 * @param {String} options.projectVersion
 * @param {String} options.buildPath Path to the build directory.
 * @param {String} options.hostname Hostname of the website where the documentation will be hosted.
 * @param {Array.<String>} options.excluded An array of urls to be excluded from the sitemap.
 * @returns {Promise.<string>} Path to the generated sitemap.
 */
module.exports = options => {
	const {
		fileName = 'sitemap.xml',
		projectSlug,
		projectVersion,
		buildPath,
		hostname,
		excluded = []
	} = options;

	// The `sitemap` package expects that `hostname` will not include subdirectories.
	// Let's split it and glue the destination URL manually.
	const { origin, pathname } = new URL( hostname );

	const { pattern, sitemapPath } = getSitemapData( { buildPath, projectSlug, fileName } );
	const sitemap = new SitemapStream( {
		hostname: origin,
		cacheTime: 600000
	} );

	const pathToFiles = globSync( pattern ).map( path => upath.normalize( path ) );

	for ( const filePath of pathToFiles ) {
		let urlForSitemap = filePath.replace( buildPath, upath.normalizeTrim( pathname ) );

		if ( projectVersion ) {
			urlForSitemap = urlForSitemap.replace( `/${ projectVersion }/`, '/latest/' );
		}

		if ( filePath.endsWith( '404.html' ) ) {
			continue;
		}

		if ( excluded.find( excluded => filePath.includes( excluded ) ) ) {
			continue;
		}

		sitemap.write( {
			url: urlForSitemap
		} );
	}

	sitemap.end();

	return streamToPromise( sitemap )
		.then( data => {
			return new Promise( ( resolve, reject ) => {
				fs.writeFile( sitemapPath, data.toString(), err => {
					if ( err ) {
						return reject( err );
					}

					return resolve( sitemapPath );
				} );
			} );
		} );
};

function getSitemapData( { buildPath, projectSlug, fileName } ) {
	return {
		pattern: projectSlug ? upath.join( buildPath, projectSlug, '**', '*.html' ) : upath.join( buildPath, '*.html' ),

		sitemapPath: upath.resolve(
			projectSlug ? upath.join( buildPath, projectSlug, fileName ) : upath.join( buildPath, fileName )
		)
	};
}
