import { FactionEntityModel } from "../features/campaign-entities/models/FactionEntityModel.js";
import { CampaignEntityIndex } from "../features/campaign-entities/services/CampaignEntityIndex.js";
import { CampaignEntityJournalStore } from "../features/campaign-entities/services/CampaignEntityJournalStore.js";
import { CampaignEntityVisibilityManager } from "../features/campaign-entities/services/CampaignEntityVisibilityManager.js";
import { FactionEmblemCatalogRegistry } from "../features/campaign-entities/services/FactionEmblemCatalogRegistry.js";
import { FactionEmblemProviderRegistry } from "../features/campaign-entities/services/FactionEmblemProviderRegistry.js";
import { FactionGeneratorRegistry } from "../features/campaign-entities/services/FactionGeneratorRegistry.js";
import { FactionEditorFieldRegistry } from "../features/campaign-entities/services/FactionEditorFieldRegistry.js";
import { FactionActionRegistry } from "../features/campaign-entities/services/FactionActionRegistry.js";
import { IdeologyCatalog } from "../features/campaign-entities/services/IdeologyCatalog.js";

export async function createFaction(data = {}) {
    return CampaignEntityJournalStore.createFaction(data);
}

export function getFaction(idOrUuid) {
    return CampaignEntityJournalStore.getFaction(idOrUuid);
}

export function getFactions(filters = {}) {
    return CampaignEntityJournalStore.getFactions(filters);
}

export function getFactionImage(idOrEntity) {
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    return entity ? FactionEntityModel.getImage(entity) : "";
}

export async function getFactionImageAsync(idOrEntity) {
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    return entity ? FactionEntityModel.getImageAsync(entity) : "";
}

export async function updateFaction(idOrUuid, patch = {}, options = {}) {
    return CampaignEntityJournalStore.updateFaction(idOrUuid, patch, options);
}

export async function deleteFaction(idOrUuid, options = {}) {
    return CampaignEntityJournalStore.deleteFaction(idOrUuid, options);
}

export async function openFactionDossier(idOrUuid) {
    const faction = getFaction(idOrUuid);
    if (!faction) {
        ui.notifications.warn("That faction could not be found.");
        return null;
    }
    if (!CampaignEntityVisibilityManager.canUserSee(faction)) {
        ui.notifications.warn("That faction is not currently visible.");
        return null;
    }
    const { FactionDossier } = await import("../features/campaign-entities/applications/FactionDossier.js");
    return FactionDossier.show({ factionId: faction.id });
}

export async function openFactionCreator(options = {}) {
    const { FactionCreationGateway } = await import("../features/campaign-entities/services/FactionCreationGateway.js");
    return FactionCreationGateway.open(options);
}

export function rebuildFactionIndex() {
    return CampaignEntityIndex.rebuild();
}

export function getFactionConnectionTarget(idOrEntity) {
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    if (!entity) return null;
    return {
        id: `nexus-entity:${entity.id}`,
        kind: "nexus-entity",
        entityId: entity.id,
        entityType: "faction",
        uuid: entity.uuid || "",
        name: FactionEntityModel.getName(entity),
        img: FactionEntityModel.getImage(entity),
        category: "faction",
        subtitle: FactionEntityModel.getSubtitle(entity)
    };
}

export function registerFactionGenerator(definition = {}) {
    return FactionGeneratorRegistry.register(definition);
}

export function registerFactionEditorSelectField(definition = {}) {
    return FactionEditorFieldRegistry.registerSelect(definition);
}

export function registerFactionAction(definition = {}) {
    return FactionActionRegistry.register(definition);
}

export function getFactionGenerators() {
    return FactionGeneratorRegistry.list();
}

export function getFactionGeneratorOptions(generatorId) {
    return FactionGeneratorRegistry.getOptions(generatorId);
}

export function getFactionGeneratorProfileOptions(generatorId, context = {}) {
    return FactionGeneratorRegistry.getProfileOptions(generatorId, context);
}

export function generateFaction(generatorId, options = {}) {
    return FactionGeneratorRegistry.generate(generatorId, options);
}

export function canRerollFactionCurrentThread(idOrEntity) {
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    return !!entity && FactionGeneratorRegistry.canRerollCurrentThread(entity.generation?.generatorId);
}

export async function rerollFactionCurrentThread(idOrEntity, options = {}) {
    if (!game.user?.isGM) return null;
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    if (!entity) return null;
    const generatorId = String(entity.generation?.generatorId || "").trim();
    if (!FactionGeneratorRegistry.canRerollCurrentThread(generatorId)) return null;

    const result = await FactionGeneratorRegistry.rerollCurrentThread(generatorId, {
        entity,
        seed: String(options.seed || "")
    });
    if (!result || typeof result !== "object" || Array.isArray(result)) return null;

    const profile = {};
    for (const key of ["drive", "action", "theme", "focus"]) {
        if (Object.hasOwn(result, key)) profile[key] = String(result[key] || "").trim();
    }
    if (!Object.keys(profile).length) return null;
    return updateFaction(entity.id, { profile });
}

export function getFactionIdeologyTopics() {
    return IdeologyCatalog.getTopics({ perspective: "organization" });
}

export function registerFactionEmblemCatalog(definition = {}) {
    return FactionEmblemCatalogRegistry.register(definition);
}

export function getFactionEmblemCatalogs() {
    return FactionEmblemCatalogRegistry.list();
}

export function getFactionEmblems() {
    return FactionEmblemCatalogRegistry.getEmblems();
}

export async function openFactionDataEditor({ factionId = "", candidate = null, onSave = null, context = {} } = {}) {
    if (!game.user?.isGM || (!factionId && !candidate)) return null;
    const { FactionDataEditor } = await import("../features/campaign-entities/applications/FactionDataEditor.js");
    return FactionDataEditor.show({ factionId, candidate, onSave, context });
}

export async function openFactionIconPicker(options = {}) {
    const { FactionEmblemPicker } = await import("../features/campaign-entities/applications/FactionEmblemPicker.js");
    const picker = new FactionEmblemPicker(options);
    picker.render(true);
    return picker;
}

export function registerFactionEmblemProvider(definition = {}) {
    return FactionEmblemProviderRegistry.register(definition);
}

export function openFactionEmblemEditor(idOrEntity, options = {}) {
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    return entity ? FactionEmblemProviderRegistry.openEditor(entity, options) : false;
}

export function getFactionPlayerVisibility(idOrEntity) {
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    return CampaignEntityVisibilityManager.getPlayerVisibilityOverride(entity);
}

export async function setFactionPlayerVisibility(idOrUuid, value = "inherit") {
    return CampaignEntityVisibilityManager.setPlayerVisibilityOverride(idOrUuid, "faction", value);
}

export function canUserSeeFaction(idOrEntity, user = game.user) {
    const entity = typeof idOrEntity === "string" ? getFaction(idOrEntity) : idOrEntity;
    return CampaignEntityVisibilityManager.canUserSee(entity, user);
}
