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

'use strict';

const hexoManager = require( '../../../src/hexo-manager' );
const { shouldBuildSnippets, getSnippetPlaceholder, getSnippetSourcePaths } = require( '../../../src/helpers/snippets' );

const upath = require( 'upath' );

const SNIPPET_REGEXP = /<p>{@snippet\s+([^}]+)}<\/p>/g;
const SNIPPETS_SOURCE_DIRECTORY = '_snippets';
const SNIPPETS_DESTINATION_DIRECTORY = 'snippets';

const relativeUrl = hexo.extend.helper.store.relative_url;

/**
 * Gather data required for building snippets. See: `src/tasks/build-snippets.js`.
 */
hexo.extend.filter.register( 'after_post_render', data => {
	if ( !shouldBuildSnippets( data.projectName, hexo ) ) {
		return;
	}

	const snippetTags = getSnippetTags( data.content );

	// Mark the page as a page that contains snippets.
	data.isSnippetPage = !!snippetTags.size;

	if ( !data.isSnippetPage ) {
		return;
	}

	const snippetsData = hexo.projectGlobals.common._snippetsData;
	const copiedFilePath = upath.join( hexoManager.getSourceDir(), data.source );
	const snippetsBasePath = upath.join( hexo.source_dir, data.BASE_PATH, SNIPPETS_SOURCE_DIRECTORY );
	const outputPath = upath.join( hexo.public_dir, data.BASE_PATH, SNIPPETS_DESTINATION_DIRECTORY );

	const basePathRelative = relativeUrl( data.path, data.BASE_PATH );
	const relativeOutputPath = relativeUrl( data.path, upath.join( data.BASE_PATH, SNIPPETS_DESTINATION_DIRECTORY ) );

	if ( !snippetsData.get( data.projectName ) ) {
		snippetsData.set( data.projectName, new Set() );
	}

	const filesMap = hexo.projectGlobals.common._copiedFiles;

	for ( const snippetDetails of snippetTags ) {
		snippetsData.get( data.projectName ).add( {
			snippetSources: getSnippetSourcePaths( snippetsBasePath, snippetDetails.name ),
			snippetName: snippetDetails.name,
			snippetSize: snippetDetails.size,
			outputPath,
			basePath: basePathRelative,
			relativeOutputPath,
			destinationPath: upath.join( hexo.public_dir, data.path ),
			pageSourcePath: filesMap.get( data.projectName ).get( copiedFilePath )
		} );

		data.content = data.content.replace( snippetDetails.snippetHTML, getSnippetPlaceholder( snippetDetails.name ) );
	}
}, 35 );

/**
 * Returns a Set that contains all snippet tags found on given page.
 *
 * @param {String} content HTML code built by Hexo based on Markdown file.
 * @returns {Set<Object.<String, String>>}
 */
function getSnippetTags( content ) {
	const snippetTags = new Set();

	let match;

	while ( ( match = SNIPPET_REGEXP.exec( content ) ) ) {
		const snippetParams = match[ 1 ].split( ' ' );

		snippetTags.add( {
			snippetHTML: match[ 0 ],
			name: snippetParams[ 0 ],
			size: snippetParams[ 1 ] || 'normal'
		} );
	}

	return snippetTags;
}

/**
 * @typedef {Object} Snippet
 *
 * @property {SnippetSource} snippetSources Sources of the snippet.
 *
 * @property {String} snippetName Name of the snippet. Defined directly after `@snippet` tag.
 *
 * @property {String} outputPath An absolute path where to write file produced by the `snippetAdapter`.
 *
 * @property {String} basePath Relative path from the processed file to the root of the documentation.
 *
 * @property {String} relativeOutputPath The same like `basePath` but for the output path (where processed file will be saved).
 *
 * @property {String} destinationPath An absolute path to the file where the snippet is being used.
 *
 * @property {String} pageSourcePath An absolute path to the source file that is being parsed.
 */

/**
 * @typedef {Object} SnippetSource
 *
 * @property {String} html An absolute path to the HTML sample.
 *
 * @property {String} css An absolute path to the CSS sample.
 *
 * @property {String} js An absolute path to the JS sample.
 */
