import { PlaceHierarchyModel } from "../models/PlaceHierarchyModel.js";
import { PlaceTypeRegistry } from "./PlaceTypeRegistry.js";

export class PlaceParentService {
    static async setParent(childKey, parentKey = null) {
        const nodes = PlaceTypeRegistry.getNodes({ isGM: true, includeHidden: true });
        const child = nodes.find(node => node.key === childKey);
        if (!child) throw new Error("The child place could not be found.");
        const provider = PlaceTypeRegistry.get(child.type);
        if (!provider?.setParent) throw new Error(`Place type "${child.type}" cannot be reparented.`);

        const validation = this.validate({ nodes, childKey, childType: child.type, parentKey });
        if (!validation.valid) throw new Error(validation.message);
        return provider.setParent(child, validation.parent);
    }

    static validate({ nodes = null, childKey = null, childType = "location", parentKey = null } = {}) {
        const allNodes = nodes || PlaceTypeRegistry.getNodes({ isGM: true, includeHidden: true });
        const provider = PlaceTypeRegistry.get(childType);
        const projectedParentKey = PlaceTypeRegistry.resolveProjectionKey(parentKey, allNodes);
        const parent = projectedParentKey ? allNodes.find(node => node.key === projectedParentKey) : null;
        if (parentKey && !parent) return { valid: false, parent: null, message: "The parent place could not be found." };
        if (parent && !(provider?.allowedParentTypes || []).includes(parent.type)) {
            return { valid: false, parent, message: `A ${childType} cannot be nested beneath a ${parent.type}.` };
        }
        if (parent && childKey && PlaceHierarchyModel.getBranch(allNodes, childKey).some(node => node.key === parent.key)) {
            return { valid: false, parent, message: "That parent would create a place hierarchy cycle." };
        }
        return { valid: true, parent, message: "" };
    }

    static getParentOptions({ childType = "location", childKey = null, selectedKey = null } = {}) {
        const nodes = PlaceTypeRegistry.getNodes({ isGM: true, includeHidden: true });
        const provider = PlaceTypeRegistry.get(childType);
        const allowedTypes = new Set(provider?.allowedParentTypes || []);
        const excluded = childKey
            ? new Set(PlaceHierarchyModel.getBranch(nodes, childKey).map(node => node.key))
            : new Set();
        const projectedSelectedKey = PlaceTypeRegistry.resolveProjectionKey(selectedKey, nodes);
        return PlaceHierarchyModel.buildRows(nodes)
            .filter(node => allowedTypes.has(node.type) && !excluded.has(node.key))
            .map(node => {
                const isProjectedSelection = !!selectedKey
                    && selectedKey !== projectedSelectedKey
                    && node.key === projectedSelectedKey;
                return {
                    id: isProjectedSelection ? selectedKey : node.key,
                    label: `${"â€” ".repeat(Math.min(node.depth, 4))}${node.name}${isProjectedSelection ? " (via linked Scene)" : ""}`,
                    selected: node.key === projectedSelectedKey,
                    type: isProjectedSelection ? "scene" : node.type
                };
            });
    }
}