import {UtilApplications} from "./UtilApplications.js";
import {SharedConsts} from "../shared/SharedConsts.js";
import {Config} from "./Config.js";
import {DataConverter} from "./DataConverter.js";
import {Vetools} from "./Vetools.js";
import {UtilCompendium} from "./UtilCompendium.js";
import {UtilActiveEffects} from "./UtilActiveEffects.js";

class DataConverterOptionalfeature {
	/**
	 * @param optFeature
	 * @param [opts] Options object.
	 * @param [opts.isAddPermission]
	 * @param [opts.isActorItem]
	 * @param [opts.actor]
	 */
	static async pGetOptionalFeatureItem (optFeature, opts) {
		opts = opts || {};
		if (opts.actor) opts.isActorItem = true;

		let pOut;
		if (await this._pIsInSrd(optFeature, opts)) {
			pOut = this._pGetOptionalFeatureItem_fromSrd(optFeature, opts);
		} else {
			pOut = this._pGetOptionalFeatureItem_other(optFeature, opts);
		}
		return pOut;
	}

	static async _pIsInSrd (optFeature) {
		const srdData = await UtilCompendium.getSrdCompendiumEntity("optionalfeature", optFeature, {fnGetAliases: this._getSrdAliases});
		return !!srdData;
	}

	static async _pGetOptionalFeatureItem_fromSrd (optFeature, opts) {
		const srdData = await UtilCompendium.getSrdCompendiumEntity("optionalfeature", optFeature, {fnGetAliases: this._getSrdAliases});

		const descriptionValue = this._getDescriptionValue(optFeature);
		const additionalData = await this._pGetAdditionalData(optFeature);

		const out = {
			name: UtilApplications.getCleanEntityName(DataConverter.getNameWithSourcePart(optFeature, {isActorItem: opts.isActorItem})),
			type: srdData.type,
			data: {
				...srdData.data,

				source: DataConverter.getSourceWithPagePart(optFeature),
				description: {value: descriptionValue, chat: "", unidentified: ""},

				...additionalData,
			},
			permission: {default: 0},
			img: await this._pGetImagePath(optFeature),
			flags: this._getOptionalFeatureFlags(optFeature, opts),
			effects: MiscUtil.copy(srdData.effects || []),
		};

		if (opts.isAddPermission) out.permission = {default: Config.get("importOptionalFeature", "permissions")};

		return out;
	}

	static async _pGetOptionalFeatureItem_other (optFeature, opts) {
		const descriptionValue = this._getDescriptionValue(optFeature);

		const tempAdditionalData = optFeature._foundryData || {}; // This is passed in from the class importer
		const additionalData = await this._pGetAdditionalData(optFeature);

		const out = {
			name: UtilApplications.getCleanEntityName(DataConverter.getNameWithSourcePart(optFeature, {isActorItem: opts.isActorItem})),
			data: {
				source: DataConverter.getSourceWithPagePart(optFeature),
				description: {value: descriptionValue, chat: "", unidentified: ""},

				activation: {type: "", cost: 0, condition: ""},
				duration: {value: 0, units: ""},
				target: {value: 0, units: "", type: ""},
				range: {value: 0, long: 0, units: null},
				uses: {value: 0, max: 0, per: ""},
				ability: "",
				actionType: "",
				attackBonus: 0,
				chatFlavor: "",
				critical: null,
				damage: {parts: [], versatile: ""},
				formula: "",
				save: {ability: "", dc: null},
				requirements: tempAdditionalData.requirements || "",
				recharge: {value: 0, charged: true},

				...additionalData,
			},
			permission: {default: 0},
			type: "feat",
			img: await this._pGetImagePath(optFeature),
			flags: this._getOptionalFeatureFlags(optFeature, opts),
			effects: [],
		};

		if (opts.isAddPermission) out.permission = {default: Config.get("importOptionalFeature", "permissions")};

		return out;
	}

	static _getDescriptionValue (optFeature) {
		if (!Config.get("importOptionalFeature", "isImportDescription")) return "";

		return DataConverter.getWithDescriptionPlugins(() => {
			const prerequisite = Renderer.utils.getPrerequisiteText(optFeature.prerequisite);
			return `<div>
				${prerequisite ? `<p><i>${prerequisite}</i></p>` : ""}
				${Renderer.get().setFirstSection(true).render({entries: optFeature.entries}, 2)}
			</div>`;
		});
	}

	static _getOptionalFeatureFlags (optFeature, opts) {
		opts = opts || {};

		const out = {
			[SharedConsts.MODULE_NAME_FAKE]: {
				page: UrlUtil.PG_OPT_FEATURES,
				source: optFeature.source,
				hash: UrlUtil.URL_TO_HASH_BUILDER[UrlUtil.PG_OPT_FEATURES](optFeature),
			},
		};

		if (opts.isAddDataFlags) {
			out[SharedConsts.MODULE_NAME_FAKE].propDroppable = "optionalfeature";
			out[SharedConsts.MODULE_NAME_FAKE].filterValues = opts.filterValues;
		}

		return out;
	}

	static async pMutActorUpdateOptionalFeature (actor, actorUpdate, optFeature, dataBuilderOpts) {
		const sideData = await this.pGetSideData(optFeature);
		DataConverter.mutActorUpdate(actor, actorUpdate, optFeature, {sideData});
	}

	static async _pGetImagePath (optFeature) {
		const fromCompendium = await UtilCompendium.pGetCompendiumImage("optionalfeature", optFeature, {fnGetAliases: this._getSrdAliases});
		if (fromCompendium) return fromCompendium;

		return `modules/${SharedConsts.MODULE_NAME}/media/icon/skills.svg`;
	}

	static async pPreloadSideData () {
		DataConverterOptionalfeature._SIDE_DATA = await Vetools.pGetOptionalFeatureSideData();
	}

	static async pGetSideData (optFeature) {
		return DataConverter.pGetSideData_(
			optFeature,
			{
				propBrew: "foundryOptionalfeature",
				fnLoadJson: async () => DataConverterOptionalfeature._SIDE_DATA || Vetools.pGetOptionalFeatureSideData(),
				propJson: "optionalfeature",
			},
		);
	}

	static async _pGetAdditionalData (optFeature) {
		return DataConverter.pGetAdditionalData_(optFeature, {propBrew: "foundryOptionalfeature", fnLoadJson: Vetools.pGetOptionalFeatureSideData, propJson: "optionalfeature"});
	}

	static async pHasOptionalFeatureSideLoadedEffects (actor, optFeature) {
		return (await DataConverter.pGetAdditionalEffectsRaw_(optFeature, {propBrew: "foundryOptionalfeature", fnLoadJson: Vetools.pGetOptionalFeatureSideData, propJson: "optionalfeature"}))?.length > 0;
	}

	static async pGetOptionalFeatureItemEffects (actor, optFeature, sheetItem, {additionalData} = {}) {
		const effectsRaw = await DataConverter.pGetAdditionalEffectsRaw_(optFeature, {propBrew: "foundryOptionalfeature", fnLoadJson: Vetools.pGetOptionalFeatureSideData, propJson: "optionalfeature"});
		return UtilActiveEffects.getExpandedEffects(effectsRaw || [], {actor, sheetItem, parentName: optFeature.name, additionalData});
	}

	static _getSrdAliases (entity) {
		if (!entity.name || !entity.srd) return [];

		const out = [];

		for (const [featureTypeSet, fnGetName] of DataConverterOptionalfeature._FEATURE_TYPES.entries()) {
			if (entity.featureType.some(it => featureTypeSet.has(it))) out.push(fnGetName(entity));
		}

		return out;
	}
}
DataConverterOptionalfeature._SIDE_DATA = null;

DataConverterOptionalfeature._FEATURE_TYPES = new Map();
DataConverterOptionalfeature._FEATURE_TYPES.set(new Set(["EI"]), entity => `Invocation: ${entity.name}`);
DataConverterOptionalfeature._FEATURE_TYPES.set(new Set(["MM"]), entity => `Metamagic: ${entity.name}`);
DataConverterOptionalfeature._FEATURE_TYPES.set(new Set(["FS:F", "FS:B", "FS:P", "FS:R"]), entity => `Fighting Style: ${entity.name}`);

export {DataConverterOptionalfeature};
