import { NexusDeletionConfirmation } from "../../deletion/applications/NexusDeletionConfirmation.js";
import { NexusDeletionProgressApplication } from "../../deletion/applications/NexusDeletionProgressApplication.js";
import { NexusDeletionPlanBuilder } from "../../deletion/services/NexusDeletionPlanBuilder.js";
import { NexusSceneDeletionCoordinator } from "../../nexus/services/NexusSceneDeletionCoordinator.js";
import { RegionProviderRegistry } from "./RegionProviderRegistry.js";
import { RegionChronicleService } from "./RegionChronicleService.js";
import { RegionPopulationRunStore } from "./RegionPopulationRunStore.js";
import { CampaignEntityJournalStore } from "../../campaign-entities/services/CampaignEntityJournalStore.js";
import { ConnectionStore } from "../../connections/services/ConnectionStore.js";

export class RegionPopulationClearService {
    static async clear(scene, { confirmed = false, purpose = "clear" } = {}) {
        const isClearOnly = purpose === "clear";
        const run = RegionPopulationRunStore.get(scene);
        if (!scene?.id) return true;
        if (!run) {
            return true;
        }

        const manifests = run.runs?.length ? run.runs : [run];
        const locationIds = [...new Set(manifests.flatMap(manifest => manifest.locationIds || []))];
        const npcIds = [...new Set(manifests.flatMap(manifest => manifest.npcIds || []))];
        const factionIds = [...new Set(manifests.flatMap(manifest => manifest.factionIds || []))];
        const connectionIds = [...new Set(manifests.flatMap(manifest => manifest.connectionIds || []))];
        const roadContributionIds = [...new Set(manifests.map(manifest => manifest.roadContributionId).filter(Boolean))];
        const overlayContributionIds = [...new Set(manifests.map(manifest => manifest.overlayContributionId).filter(Boolean))];
        const plan = NexusDeletionPlanBuilder.buildForLocations(locationIds);
        const provider = RegionProviderRegistry.get(run.regionProviderId);
        const roadImpact = typeof provider?.getRoadContributionImpact === "function"
            ? (await Promise.all(roadContributionIds.map(id => provider.getRoadContributionImpact(scene, id)))).reduce((sum, value) => sum + Number(value || 0), 0)
            : 0;
        const overlayImpact = typeof provider?.getCellOverlayContributionImpact === "function"
            ? (await Promise.all(overlayContributionIds.map(id => provider.getCellOverlayContributionImpact(scene, id)))).reduce((sum, value) => sum + Number(value || 0), 0)
            : 0;
        const chronicleImpact = RegionChronicleService.getEntry(scene, run) ? 1 : 0;
        const generatedEntityIds = new Set([...npcIds, ...factionIds]);
        const generatedCandidates = (plan.entityCandidates || []).filter(row => generatedEntityIds.has(row.id));
        const seededCandidates = (plan.entityCandidates || []).filter(row => !generatedEntityIds.has(row.id));
        const confirmationPlan = {
            ...plan,
            entityCandidates: generatedCandidates,
            preservedEntities: [
                ...(plan.preservedEntities || []),
                ...seededCandidates.map(row => ({
                    ...row,
                    reasons: [...new Set([...(row.reasons || []), "existed before regional development"])]
                }))
            ]
        };
        const participantImpacts = [
            ...(roadImpact > 0 ? [{ label: "generated road segment", count: roadImpact }] : []),
            ...(overlayImpact > 0 ? [{ label: "generated land overlay", count: overlayImpact }] : []),
            ...(npcIds.length ? [{ label: "generated person", count: npcIds.length }] : []),
            ...(factionIds.length ? [{ label: "generated faction", count: factionIds.length }] : []),
            ...(connectionIds.length ? [{ label: "generated connection", count: connectionIds.length }] : []),
            ...(chronicleImpact ? [{ label: "regional chronicle", count: chronicleImpact }] : [])
        ];
        const decision = confirmed
            ? {
                confirmed: true,
                selectedEntityIds: NexusDeletionConfirmation.getDefaultSelection(confirmationPlan)
            }
            : await NexusDeletionConfirmation.confirm(confirmationPlan, {
                title: isClearOnly ? "Clear Generated Population" : "Replace Generated Population",
                message: isClearOnly ? `Permanently delete the generated population on <strong>${foundry.utils.escapeHTML(scene.name)}</strong>?` : `Generating again will permanently delete the population previously generated on <strong>${foundry.utils.escapeHTML(scene.name)}</strong>.`,
                participantImpacts,
                warning: "Generated additions will be permanently deleted. Pre-existing people and factions are protected; development changes applied to pre-existing Locations remain part of those Locations.",
                confirmLabel: isClearOnly ? "Clear Generated" : "Delete and Regenerate"
            });
        if (!decision) return false;
        const candidateIds = new Set((plan.entityCandidates || []).map(row => row.id));
        const selectedEntityIds = new Set(decision.selectedEntityIds || []);
        const shouldDeleteEntity = id => !candidateIds.has(id) || selectedEntityIds.has(id);

        const canRemoveRoads = roadContributionIds.length && typeof provider?.removeRoadContribution === "function";
        const canRemoveOverlays = overlayContributionIds.length && typeof provider?.removeCellOverlayContribution === "function";
        const roadWork = canRemoveRoads ? Math.max(1, Number(roadImpact || 0)) : 0;
        const overlayWork = canRemoveOverlays ? Math.max(1, Number(overlayImpact || 0)) : 0;
        const chronicleWork = chronicleImpact;
        const progress = new NexusDeletionProgressApplication();
        progress.addTotal(roadWork + overlayWork + chronicleWork + npcIds.length + factionIds.length + connectionIds.length + 1);
        await progress.open();

        try {
            const deletionResult = (plan.locations || []).length
                ? await NexusSceneDeletionCoordinator.executePlan(plan, {
                    intent: "replace-region-population",
                    source: "region-population",
                    selectedEntityIds: decision.selectedEntityIds || [],
                    progress
                })
                : true;
            if (deletionResult === false) {
                await progress.closeProgress();
                return false;
            }
            const alreadyDeletedEntityIds = new Set(deletionResult?.deletedEntityIds || []);

            if (canRemoveRoads) {
                progress.setMessage("Deleting generated roads...");
                for (const contributionId of [...roadContributionIds].reverse()) {
                    await provider.removeRoadContribution(scene, contributionId);
                }
                const remainingRoads = typeof provider.getRoadContributionImpact === "function"
                    ? (await Promise.all(roadContributionIds.map(id => provider.getRoadContributionImpact(scene, id)))).reduce((sum, value) => sum + Number(value || 0), 0)
                    : 0;
                if (remainingRoads > 0) {
                    throw new Error(`${remainingRoads} road segment${remainingRoads === 1 ? "" : "s"} could not be deleted.`);
                }
                progress.advance(roadWork);
            }
            if (canRemoveOverlays) {
                progress.setMessage("Deleting generated land overlays...");
                for (const contributionId of [...overlayContributionIds].reverse()) {
                    await provider.removeCellOverlayContribution(scene, contributionId);
                }
                progress.advance(overlayWork);
            }
            const remainingConnectionIds = connectionIds.filter(connectionId => ConnectionStore.getConnectionEdge(connectionId));
            if (remainingConnectionIds.length) {
                progress.setMessage("Deleting generated connections...");
                await ConnectionStore.removeConnections(remainingConnectionIds, { reason: "clearRegionPopulation" });
            }
            progress.advance(connectionIds.length);
            for (const npcId of npcIds) {
                if (shouldDeleteEntity(npcId) && !alreadyDeletedEntityIds.has(npcId)) {
                    await CampaignEntityJournalStore.deleteNpc(npcId);
                }
                progress.advance(1);
            }
            for (const factionId of factionIds) {
                if (shouldDeleteEntity(factionId) && !alreadyDeletedEntityIds.has(factionId)) {
                    await CampaignEntityJournalStore.deleteFaction(factionId);
                }
                progress.advance(1);
            }
            if (chronicleWork) {
                progress.setMessage("Deleting the regional chronicle...");
                await RegionChronicleService.delete(scene, run);
                progress.advance(chronicleWork);
            }
            progress.setMessage("Clearing generated population records...");
            await RegionPopulationRunStore.clear(scene);
            progress.advance(1);
            await progress.complete("Generated population deleted.");
            return true;
        } catch (error) {
            await progress.closeProgress();
            throw error;
        }
    }
}
