import { ConnectionOpinionModel } from "../models/ConnectionOpinionModel.js";
import { registerCoreOpinionInfluenceProviders, resolveOpinionEntity } from "./CoreOpinionInfluenceProviders.js";
import { ConnectionStore } from "./ConnectionStore.js";
import { ConnectionTargetResolver } from "./ConnectionTargetResolver.js";
import { OpinionInfluenceProviderRegistry } from "./OpinionInfluenceProviderRegistry.js";

export class ConnectionOpinionResolver {
    static resolve(edgeOrId) {
        registerCoreOpinionInfluenceProviders();
        const edge = typeof edgeOrId === "string" ? ConnectionStore.getConnectionEdge(edgeOrId) : edgeOrId;
        if (!edge || !ConnectionOpinionModel.isTracked(edge)) return null;

        return {
            edgeId: edge.id,
            tracked: true,
            perspectives: {
                [edge.sourceNodeId]: this.resolvePerspective(edge, edge.sourceNodeId),
                [edge.targetNodeId]: this.resolvePerspective(edge, edge.targetNodeId)
            }
        };
    }

    static resolvePerspective(edgeOrId, observerNodeId = "") {
        registerCoreOpinionInfluenceProviders();
        const edge = typeof edgeOrId === "string" ? ConnectionStore.getConnectionEdge(edgeOrId) : edgeOrId;
        if (!edge || !ConnectionOpinionModel.isTracked(edge)) return null;

        const subjectNodeId = ConnectionOpinionModel.getSubjectNodeId(edge, observerNodeId);
        if (!subjectNodeId) return null;
        const observerNode = ConnectionStore.getNode(observerNodeId);
        const subjectNode = ConnectionStore.getNode(subjectNodeId);
        if (!observerNode || !subjectNode) return null;

        const observerDisplay = ConnectionTargetResolver.resolveDisplayNodeSync(observerNode) || observerNode;
        const subjectDisplay = ConnectionTargetResolver.resolveDisplayNodeSync(subjectNode) || subjectNode;
        const persisted = ConnectionOpinionModel.getPerspective(edge.opinions, observerNodeId);
        const adjustmentTotal = persisted.adjustments.reduce((sum, adjustment) => sum + adjustment.value, 0);
        const automaticInfluences = OpinionInfluenceProviderRegistry.resolve({
            edge,
            observerNode,
            subjectNode,
            observerEntity: resolveOpinionEntity(observerNode),
            subjectEntity: resolveOpinionEntity(subjectNode)
        });
        const automaticTotal = automaticInfluences.reduce((sum, influence) => sum + influence.value, 0);
        const score = ConnectionOpinionModel.clampScore(persisted.base + adjustmentTotal + automaticTotal);
        const tier = ConnectionOpinionModel.getTier(score);

        return {
            edgeId: edge.id,
            observerNodeId,
            subjectNodeId,
            observer: this.#nodeContext(observerDisplay),
            subject: this.#nodeContext(subjectDisplay),
            base: persisted.base,
            adjustments: persisted.adjustments,
            adjustmentTotal,
            automaticInfluences,
            automaticTotal,
            score,
            scoreLabel: score > 0 ? `+${score}` : String(score),
            tier
        };
    }

    static #nodeContext(node = {}) {
        return {
            id: node.id || "",
            name: node.name || "Unknown",
            img: node.img || "",
            entityType: node.entityType || "",
            missing: !!node.missing
        };
    }
}
