import { ShipOwnershipModel } from "../models/ShipOwnershipModel.js";
import { ConnectionStore } from "./ConnectionStore.js";
import { ConnectionTargetResolver } from "./ConnectionTargetResolver.js";

export class ShipOwnershipService {
    static getOwner(shipTarget, { user = game.user, includeHidden = false } = {}) {
        const shipNodeId = ConnectionTargetResolver.getNodeId(shipTarget);
        const entry = this.#entries(shipNodeId)[0] || null;
        if (!entry) return null;
        if (!includeHidden && !ConnectionStore.canUserSeeConnection(entry.edge, user)) return null;
        if (!includeHidden && !ConnectionTargetResolver.canUserSeeNode(entry.otherNode, user)) return null;
        const display = ConnectionTargetResolver.resolveDisplayNodeSync(entry.otherNode) || entry.otherNode;
        return {
            edgeId: entry.edge.id,
            edge: entry.edge,
            shipNodeId: entry.ownership.shipNodeId,
            ownerNodeId: entry.ownership.ownerNodeId,
            owner: {
                nodeId: entry.otherNode.id,
                entityId: entry.otherNode.entityId || "",
                entityType: entry.otherNode.entityType || "",
                name: display.name || "Unknown Owner",
                imageSrc: display.img || "",
                subtitle: display.subtitle || (entry.otherNode.entityType === "faction" ? "Organization" : "Owner")
            }
        };
    }

    static getShipsForOwner(ownerTarget, { user = game.user, includeHidden = false } = {}) {
        const ownerNodeId = ConnectionTargetResolver.getNodeId(ownerTarget);
        if (!ownerNodeId) return [];
        return this.#entries(ownerNodeId)
            .filter(entry => entry.ownership.ownerNodeId === ownerNodeId)
            .filter(entry => includeHidden || ConnectionStore.canUserSeeConnection(entry.edge, user))
            .filter(entry => includeHidden || ConnectionTargetResolver.canUserSeeNode(entry.otherNode, user))
            .map(entry => {
                const display = ConnectionTargetResolver.resolveDisplayNodeSync(entry.otherNode) || entry.otherNode;
                return {
                    edgeId: entry.edge.id,
                    shipNodeId: entry.ownership.shipNodeId,
                    ownerNodeId: entry.ownership.ownerNodeId,
                    ship: {
                        nodeId: entry.otherNode.id,
                        entityId: entry.otherNode.entityId || "",
                        name: display.name || "Unknown Ship",
                        imageSrc: display.img || "",
                        subtitle: display.subtitle || "Ship"
                    }
                };
            });
    }

    static async setOwner(shipTarget, ownerTarget, { edgeId = "" } = {}) {
        if (!game.user?.isGM) return null;
        const endpoints = this.#endpoints(shipTarget, ownerTarget);
        if (!endpoints) throw new Error("Ship ownership requires a Ship and a Person or Organization.");
        const selected = edgeId ? ConnectionStore.getConnectionEdge(edgeId) : this.#findEdge(endpoints.shipNode.id, endpoints.ownerNode.id);
        const shipOwnership = ShipOwnershipModel.create(endpoints.shipNode, endpoints.ownerNode, {
            managedConnection: selected?.shipOwnership?.managedConnection === true || !selected,
            previousViews: selected?.shipOwnership?.previousViews || (selected ? selected.views : null)
        });
        const ownerIsFaction = endpoints.ownerNode.entityType === "faction";
        const views = {
            ...(selected?.views || {}),
            [endpoints.shipNode.id]: { ...(selected?.views?.[endpoints.shipNode.id] || {}), category: ownerIsFaction ? "faction" : "npc", role: "Owned By" },
            [endpoints.ownerNode.id]: { ...(selected?.views?.[endpoints.ownerNode.id] || {}), category: "ship", role: `Owns ${endpoints.shipNode.name || "Ship"}` }
        };

        return ConnectionStore.runBatch(async () => {
            for (const current of this.#entries(endpoints.shipNode.id)) {
                if (current.edge.id !== selected?.id) await this.#clearEntry(current);
            }
            if (selected) return ConnectionStore.updateConnection(selected.id, { relationType: "ship-owner", shipOwnership, views });
            return ConnectionStore.addConnection(endpoints.shipNode, endpoints.ownerNode, {
                relationType: "ship-owner",
                shipOwnership,
                sourceView: views[endpoints.shipNode.id],
                targetView: views[endpoints.ownerNode.id]
            });
        }, { reason: "setShipOwner" });
    }

    static async clearOwner(shipTarget) {
        if (!game.user?.isGM) return false;
        const current = this.getOwner(shipTarget, { includeHidden: true });
        if (!current) return false;
        await this.#clearEntry({ edge: current.edge, ownership: current.edge.shipOwnership });
        return true;
    }

    static #entries(nodeId = "") {
        return (ConnectionStore.getGraphContext().adjacency.get(nodeId) || [])
            .map(({ edge, node }) => ({ edge, otherNode: node, ownership: edge.shipOwnership }))
            .filter(entry => !!entry.ownership)
            .sort((left, right) => Number(left.edge.createdTime || 0) - Number(right.edge.createdTime || 0) || String(left.edge.id).localeCompare(String(right.edge.id)));
    }

    static #endpoints(left, right) {
        return ShipOwnershipModel.resolveEndpoints(this.#nodeLike(left), this.#nodeLike(right));
    }

    static #nodeLike(target) {
        const id = ConnectionTargetResolver.getNodeId(target);
        return id ? { ...(ConnectionStore.getNode(id) || {}), ...target, id } : null;
    }

    static #findEdge(leftNodeId, rightNodeId) {
        return (ConnectionStore.getGraphContext().adjacency.get(leftNodeId) || []).find(({ node }) => node.id === rightNodeId)?.edge || null;
    }

    static async #clearEntry(entry) {
        if (!entry?.edge?.id) return false;
        if (entry.ownership?.managedConnection === true) return ConnectionStore.removeConnection(entry.edge.id);
        return ConnectionStore.updateConnection(entry.edge.id, {
            shipOwnership: null,
            relationType: entry.edge.relationType === "ship-owner" ? "" : entry.edge.relationType,
            views: entry.ownership?.previousViews || entry.edge.views
        });
    }
}
