<?php
declare( strict_types = 1 );

namespace MediaWiki\Extension\Translate\MessageGroupProcessing;

use ApiQuery;
use ApiQueryBase;
use MediaWiki\Extension\Translate\MessageSync\MessageSourceChange;
use MediaWiki\Extension\Translate\Synchronization\MessageChangeStorage;
use MediaWiki\Extension\Translate\Utilities\StringComparators\EditDistanceStringComparator;
use MediaWiki\Extension\Translate\Utilities\Utilities;
use MediaWiki\Title\Title;
use Wikimedia\ParamValidator\ParamValidator;

/**
 * API module for querying message group changes.
 * @author Abijeet Patro
 * @since 2019.10
 * @license GPL-2.0-or-later
 * @ingroup API TranslateAPI
 */
class QueryManageMessageGroupsActionApi extends ApiQueryBase {
	private const RIGHT = 'translate-manage';

	public function __construct( ApiQuery $query, string $moduleName ) {
		parent::__construct( $query, $moduleName, 'mmg' );
	}

	public function execute() {
		$params = $this->extractRequestParams();
		$groupId = $params['groupId'];
		$msgKey = $params['messageKey'];
		$name = $params['changesetName'] ?? MessageChangeStorage::DEFAULT_NAME;

		$user = $this->getUser();
		$allowed = $user->isAllowed( self::RIGHT );

		if ( !$allowed ) {
			$this->dieWithError( 'apierror-permissiondenied-generic', 'permissiondenied' );
		}

		$group = MessageGroups::getGroup( $groupId );
		if ( !$group ) {
			$this->dieWithError( 'apierror-translate-invalidgroup', 'invalidgroup' );
		}

		if ( !MessageChangeStorage::isValidCdbName( $name ) ) {
			$this->dieWithError(
				[ 'apierror-translate-invalid-changeset-name', wfEscapeWikiText( $name ) ],
				'invalidchangeset'
			);
		}
		$cdbPath = MessageChangeStorage::getCdbPath( $name );

		$sourceChanges = MessageChangeStorage::getGroupChanges( $cdbPath, $groupId );

		if ( $sourceChanges->getAllModifications() === [] ) {
			$this->dieWithError( [ 'apierror-translate-smg-nochanges' ] );
		}

		$messages = $this->getPossibleRenames(
			$sourceChanges, $group->getNamespace(), $msgKey, $group->getSourceLanguage()
		);

		$result = $this->getResult();
		$result->addValue( [ 'query', $this->getModuleName() ], null, $messages );
	}

	/** Fetches the messages that can be used as possible renames for a given message. */
	protected function getPossibleRenames(
		MessageSourceChange $sourceChanges,
		int $groupNamespace,
		string $msgKey,
		string $languageCode
	): array {
		$deletions = $sourceChanges->getDeletions( $languageCode );
		$targetMsg = $sourceChanges->findMessage(
			$languageCode, $msgKey, [ MessageSourceChange::ADDITION, MessageSourceChange::RENAME ]
		);
		$stringComparator = new EditDistanceStringComparator();
		$renameList = [];

		// compare deleted messages with the target message and get the similarity.
		foreach ( $deletions as $deletion ) {
			if ( $deletion['content'] === null ) {
				continue;
			}

			$similarity = $stringComparator->getSimilarity(
				$deletion['content'],
				// @phan-suppress-next-line PhanTypeArraySuspiciousNullable
				$targetMsg['content']
			);

			$title = Title::makeTitle(
				$groupNamespace,
				Utilities::title( $deletion['key'], $languageCode, $groupNamespace )
			);

			$renameList[] = [
				'key' => $deletion['key'],
				'content' => $deletion['content'],
				'similarity' => $similarity,
				'link' => $title->getFullURL(),
				'title' => $title->getPrefixedText()
			];
		}

		// sort them based on similarity
		usort( $renameList, static function ( $a, $b ) {
			return -( $a['similarity'] <=> $b['similarity'] );
		} );

		return $renameList;
	}

	protected function getAllowedParams(): array {
		$params = parent::getAllowedParams();
		$params['groupId'] = [
			ParamValidator::PARAM_TYPE => 'string',
			ParamValidator::PARAM_REQUIRED => true,
		];

		$params['messageKey'] = [
			ParamValidator::PARAM_TYPE => 'string',
			ParamValidator::PARAM_REQUIRED => true,
		];

		$params['changesetName'] = [
			ParamValidator::PARAM_TYPE => 'string',
			ParamValidator::PARAM_DEFAULT => MessageChangeStorage::DEFAULT_NAME
		];

		return $params;
	}

	protected function getExamplesMessages(): array {
		return [
			'action=query&meta=managemessagegroup&mmggroupId=hello
				&mmgchangesetName=default&mmgmessageKey=world' => 'apihelp-query+managemessagegroups-example-1',
		];
	}
}
