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

'use strict';

const cheerio = require( 'cheerio' );
const fs = require( 'fs' );
const path = require( 'path' );

const HexoManager = require( '../../src/hexo-manager' );

/**
 * Cache for parsed SVG elements.
 */
const SVG_CACHE = new Map();

module.exports = function inlineSvg( str, isDocument = true ) {
	const $ = cheerio.load( str, null, isDocument );

	// Find all elements with data-inline-svg-image attribute.
	$( '[data-inline-svg-image]' ).each( function() {
		const element = $( this );
		const svgPath = element.attr( 'data-inline-svg-image' );
		const fillColor = element.attr( 'data-inline-svg-fill-color' );
		const trimDimensions = element.attr( 'data-inline-svg-trim-dimensions' ) !== undefined;
		const title = element.attr( 'data-inline-svg-title' );

		// Construct the absolute path to the SVG file.
		// Assuming the path is relative to the Hexo root.
		const absolutePath = path.join( HexoManager.hexo.theme_dir, svgPath );

		// Read the SVG file content
		if ( !fs.existsSync( absolutePath ) ) {
			console.warn( `SVG file not found: ${ absolutePath }` );
			return;
		}

		// Generate a cache key based on file path, fill color, trim dimensions and title
		const cacheKey = JSON.stringify( {
			path: absolutePath,
			fillColor: fillColor || 'default',
			trimDimensions,
			title: title || null
		} );

		let $svg;

		// Try to get the SVG from cache first.
		if ( SVG_CACHE.has( cacheKey ) ) {
			$svg = SVG_CACHE.get( cacheKey );
		} else {
			// Parse the SVG.
			const svgContent = fs.readFileSync( absolutePath, 'utf8' );

			$svg = cheerio.load( svgContent, { xmlMode: true } )( 'svg' );

			// Apply fill color if specified.
			if ( fillColor ) {
				applyFillColor( $, $svg, fillColor );
			}

			// Remove width and height if trimDimensions is true
			if ( trimDimensions ) {
				trimSvgDimensions( $, $svg );
			}

			// Add title if specified
			if ( title ) {
				addTitle( $, $svg, title );
			}

			// Store in cache.
			SVG_CACHE.set( cacheKey, $svg );
		}

		// Copy original element's attributes to SVG.
		const elementAttributes = element.attr();
		let svgCloned = false;

		for ( const attr in elementAttributes ) {
			if ( attr.startsWith( 'data-inline-svg-' ) ) {
				continue;
			}

			if ( !svgCloned ) {
				$svg = $svg.clone();
				svgCloned = true;
			}

			$svg.attr( attr, elementAttributes[ attr ] );
		}

		// Replace the original element with the SVG.
		element.replaceWith( $svg.toString() );
	} );

	$( '[data-inline-svg-image]' ).removeAttr( 'data-spritesheet-svg' );

	return $.html();
};

/**
 * Applies fill color to an SVG element.
 */
function applyFillColor( $, $svg, fillColor ) {
	// Replace all fill attributes with the specified color.
	$svg.find( '[fill]' ).each( function() {
		$( this ).attr( 'fill', fillColor );
	} );

	// Also check the root SVG for fill attribute.
	if ( $svg.attr( 'fill' ) ) {
		$svg.attr( 'fill', fillColor );
	}

	return $svg;
}

/**
 * Removes width and height attributes from SVG elements.
 */
function trimSvgDimensions( $, $svg ) {
	$svg.removeAttr( 'width' );
	$svg.removeAttr( 'height' );
	return $svg;
}

/**
 * Adds or updates a title element in the SVG.
 */
function addTitle( $, $svg, title ) {
	if ( [ '', 'none', 'false', 'null' ].includes( title ) ) {
		return $svg;
	}

	// Check if SVG already has a title
	const existingTitle = $svg.find( 'title' );

	if ( existingTitle.length ) {
		// Update existing title
		existingTitle.text( title );
	} else {
		// Create new title and add it as the first child
		const $title = $( '<title></title>' ).text( title );
		$svg.prepend( $title );
	}

	return $svg;
}

