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

'use strict';

const { MEMBER_NAME_REGEXP, LONG_NAME_LABEL_REGEXP } = require( '../api-builder/utils/utils' );

/**
 * @param {String} longname
 * @returns {LongNameParts}
 */
module.exports = longname => {
	if ( !longname || typeof longname !== 'string' ) {
		return {};
	}

	// Processing a literal value. Let's return it without modifications.
	if ( longname.startsWith( '\'' ) && longname.endsWith( '\'' ) ) {
		return {
			isSingle: true,
			name: longname,
			longnameBase: '',
			directoryNames: []
		};
	}

	const parts = longname.split( '/' );
	let [ , nameMatch, label ] = MEMBER_NAME_REGEXP.exec( longname ) || [];

	let name = nameMatch ? nameMatch.replace( 'module:', '' ) : ''; // last part of the longname
	let longnameBase = longname.split( new RegExp( '[#.]' + name ) )[ 0 ];

	// Remove the label part from a member name.
	name = name.replace( LONG_NAME_LABEL_REGEXP, '' );

	const isStatic = longname[ longnameBase.length ] === '.' || longnameBase.startsWith( '.' ) || longnameBase.endsWith( '.' );

	// `longnameBase` might start or end with a symbol. It depends if it is a full or short link.
	longnameBase = longnameBase.replace( /^[#~.]|[#~.]$/g, '' );

	// Support for links containing a doclet type.
	// E.g., `CKEDITOR.feature#property-allowedContent`.
	if ( name.includes( '-' ) ) {
		let [ type, description ] = name.split( '-' );

		// JSDuck replaces `$` with `s-`.
		if ( type === 's' ) {
			description = `s-${ description }`;
		}

		// For events, we want to keep the `name` as it is specified.
		if ( type === 'event' ) {
			name = type;

			// An event within a namespace.
			if ( label ) {
				label = `${ description }:${ label }`;
			}
			else {
				label = description;
			}
		}
		// Otherwise, skip the type. Use the name only.
		else {
			name = description;
		}
	}

	if ( parts.length === 1 ) {
		// When processing a string that looks like an assignment expression,
		// let's return the original string (do not cut it anywhere).
		// It is useful when processing a generic argument.
		const isTypeAssignment = longname.split( '=' ).length === 2;

		if ( isTypeAssignment ) {
			return {
				isSingle: true,
				name: longname,
				longnameBase: '',
				directoryNames: []
			};
		}

		return {
			isSingle: true,
			name,
			longnameBase,
			directoryNames: [],
			label,
			isStatic
		};
	}

	const moduleAndRest = parts.pop();

	const moduleNameMatch = /[-\w]+/.exec( moduleAndRest );
	const moduleName = moduleNameMatch ? moduleNameMatch[ 0 ] : '';

	const classNameMatch = /~(\w+)/.exec( moduleAndRest );
	const className = classNameMatch ? classNameMatch[ 1 ] : '';

	const packageName = parts.length > 0 ? parts.shift().replace( 'module:', '' ) : '';
	const directoryNames = parts;

	return {
		name,
		longnameBase,
		moduleName,
		className,
		packageName,
		directoryNames,
		label,
		isStatic
	};
};

/**
 * @typedef {Object} LongNameParts
 *
 * @property {Array.<String>} [directoryNames]
 *
 * @property {Boolean} [isStatic]
 *
 * @property {Boolean} [isSingle]
 *
 * @property {String} [longnameBase]
 *
 * @property {String} [moduleName]
 *
 * @property {String} [className]
 *
 * @property {String} [packageName]
 *
 * @property {String} [name]
 *
 * @property {String} [label]
 */
