import { i18n } from '../../../plugin/i18n';

const COLORS_PALETTE = [
    '#5470c6',
    '#91cc75',
    '#fac858',
    '#ee6666',
    '#73c0de',
    '#3ba272',
    '#fc8452',
    '#9a60b4',
    '#ea7ccc'
];

const MAX_LABEL_NAME_LENGTH = 22;

function truncateLabelText(text) {
    if (!text) {
        return 'Unknown';
    }
    return text.length > MAX_LABEL_NAME_LENGTH
        ? `${text.slice(0, MAX_LABEL_NAME_LENGTH)}…`
        : text;
}

function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
}

export function computeForceOptions(nodes, links) {
    const nodeCount = nodes.length || 1;
    const degreeSum = nodes.reduce((sum, node) => sum + (node.degree || 0), 0);
    const maxSymbol = nodes.reduce(
        (max, node) => Math.max(max, node.symbolSize || 0),
        0
    );
    const avgDegree = degreeSum / nodeCount || 0;
    const density = links.length ? links.length / nodeCount : 0;

    const repulsionBase = 140 + maxSymbol * 4 + avgDegree * 6;
    const repulsion = clamp(repulsionBase, 180, 720);

    const minEdge = clamp(48 + avgDegree * 1.2, 48, 90);
    const maxEdge = clamp(
        minEdge + 60 + Math.max(0, 140 - density * 18),
        90,
        200
    );

    return {
        repulsion,
        edgeLength: [minEdge, maxEdge],
        gravity: 0.3,
        layoutAnimation: nodes.length < 1000
    };
}

export function applyForceOverrides(force, forceOverrides) {
    if (!forceOverrides) {
        return force;
    }
    const merged = { ...force };
    if (typeof forceOverrides.repulsion === 'number') {
        merged.repulsion = Math.max(0, forceOverrides.repulsion);
    }
    if (Array.isArray(forceOverrides.edgeLength)) {
        const [
            minRaw = merged.edgeLength?.[0],
            maxRaw = merged.edgeLength?.[1]
        ] = forceOverrides.edgeLength;
        const min =
            typeof minRaw === 'number' ? minRaw : merged.edgeLength?.[0];
        const max =
            typeof maxRaw === 'number' ? maxRaw : merged.edgeLength?.[1];
        const hasBoth = typeof min === 'number' && typeof max === 'number';
        if (hasBoth) {
            const normalizedMin = Math.max(0, min);
            merged.edgeLength = [normalizedMin, Math.max(normalizedMin, max)];
        }
    }
    if (typeof forceOverrides.gravity === 'number') {
        merged.gravity = clamp(forceOverrides.gravity, 0, 1);
    }
    if (typeof forceOverrides.layoutAnimation === 'boolean') {
        merged.layoutAnimation = forceOverrides.layoutAnimation;
    }
    return merged;
}

const t = i18n.global.t;

export function useMutualGraphChart({ cachedUsers, graphPayload }) {
    function buildGraph(mutualMap, updateChart) {
        const nodes = new Map();
        const links = [];
        const linkKeys = new Set();

        function ensureNode(id, name) {
            if (!id) {
                return null;
            }
            const existing = nodes.get(id);
            if (existing) {
                return existing;
            }
            const node = {
                id,
                name: name || id
            };
            nodes.set(id, node);
            return node;
        }

        function incrementDegree(nodeId) {
            const node = nodes.get(nodeId);
            if (!node) {
                return;
            }
            node.degree = (node.degree || 0) + 1;
        }

        function addLink(source, target) {
            if (!source || !target || source === target) {
                return;
            }
            const key = [source, target].sort().join('__');
            if (linkKeys.has(key)) {
                return;
            }
            linkKeys.add(key);
            links.push({ source, target });
            incrementDegree(source);
            incrementDegree(target);
        }

        for (const [friendId, { friend, mutuals }] of mutualMap.entries()) {
            const friendRef = friend?.ref || cachedUsers.get(friendId);
            const friendName = friendRef?.displayName;
            ensureNode(friendId, friendName);

            for (const mutual of mutuals) {
                if (!mutual?.id) {
                    continue;
                }
                const cached = cachedUsers.get(mutual.id);
                const label =
                    cached?.displayName || mutual.displayName || mutual.id;
                ensureNode(mutual.id, label);
                addLink(friendId, mutual.id);
            }
        }

        const nodeList = Array.from(nodes.values());
        const maxDegree = nodeList.reduce(
            (acc, node) => Math.max(acc, node.degree || 0),
            0
        );

        nodeList.forEach((node, index) => {
            const normalized = maxDegree ? (node.degree || 0) / maxDegree : 0;
            const size = Math.round(26 + normalized * 52);
            const color = COLORS_PALETTE[index % COLORS_PALETTE.length];
            const displayName = truncateLabelText(node.name || node.id);

            node.symbolSize = size;
            node.label = {
                show: true,
                formatter: displayName
            };
            node.itemStyle = {
                ...(node.itemStyle || {}),
                color
            };
        });

        graphPayload.value = {
            nodes: nodeList,
            links
        };

        updateChart?.(graphPayload.value);
    }

    function createChartOption(payload, force) {
        const nodes = payload?.nodes ?? [];
        const links = payload?.links ?? [];
        const labelMap = Object.create(null);
        nodes.forEach((node) => {
            if (node?.id) {
                labelMap[node.id] = node.name || node.id;
            }
        });

        const resolvedForce = {
            ...(force || {}),
            layoutAnimation: false
        };
        return {
            color: COLORS_PALETTE,
            backgroundColor: 'transparent',
            animation: false,
            animationDuration: 0,
            animationDurationUpdate: 0,
            tooltip: {
                trigger: 'item',
                formatter: (params) => {
                    if (params.dataType === 'node') {
                        const name =
                            params.data?.name || params.data?.id || 'Unknown';
                        const mutualCount = Number.isFinite(params.data?.degree)
                            ? params.data.degree
                            : 0;
                        const mutualLabel = t(
                            'view.charts.mutual_friend.tooltip.mutual_friends_count',
                            {
                                count: mutualCount
                            }
                        );
                        return `${name}\n${mutualLabel}`;
                    }
                }
            },
            series: [
                {
                    type: 'graph',
                    layout: 'force',
                    legendHoverLink: false,
                    roam: true,
                    roamTrigger: 'global',
                    animation: false,
                    animationDuration: 0,
                    animationDurationUpdate: 0,
                    data: nodes,
                    links,
                    label: {
                        position: 'right'
                    },
                    symbol: 'circle',
                    emphasis: {
                        focus: 'adjacency',
                        itemStyle: {
                            borderWidth: 3,
                            opacity: 1
                        }
                    },
                    force: resolvedForce,
                    itemStyle: {
                        borderColor: '#ffffff',
                        borderWidth: 1,
                        shadowBlur: 16,
                        shadowColor: 'rgba(0,0,0,0.35)'
                    },
                    lineStyle: {
                        curveness: 0.18,
                        width: 0.5,
                        opacity: 0.4
                    }
                }
            ]
        };
    }

    return {
        buildGraph,
        createChartOption
    };
}
