"""
Ontology Merge - Three-way merge for ontology versions.

Operates on raw dicts (the JSONB content), not DB models,
keeping merge logic pure and testable without a database.
"""

from __future__ import annotations

import copy
from typing import Any

from pycharter.wiki.versioning.models import OntologyMergeResult


def merge_ontologies(
    base: dict[str, Any],
    ours: dict[str, Any],
    theirs: dict[str, Any],
) -> OntologyMergeResult:
    """
    Three-way merge of ontology content.

    Merges changes from 'ours' and 'theirs' relative to a common 'base'.
    Handles field additions, removals, and modifications with conflict
    detection when both sides modify the same field differently.

    Args:
        base: Common ancestor ontology content
        ours: Our branch's ontology content
        theirs: Their branch's ontology content

    Returns:
        OntologyMergeResult with merged content or conflicts
    """
    base_fields = base.get("fields", {})
    our_fields = ours.get("fields", {})
    their_fields = theirs.get("fields", {})

    all_keys = (
        set(base_fields.keys()) | set(our_fields.keys()) | set(their_fields.keys())
    )

    merged_fields: dict[str, Any] = {}
    conflicts = []
    auto_resolved = []

    for key in sorted(all_keys):
        in_base = key in base_fields
        in_ours = key in our_fields
        in_theirs = key in their_fields

        base_val = base_fields.get(key)
        our_val = our_fields.get(key)
        their_val = their_fields.get(key)

        # Both sides unchanged from base
        if our_val == base_val and their_val == base_val:
            if in_base:
                merged_fields[key] = copy.deepcopy(base_val)
            continue

        # Only ours changed
        if our_val != base_val and their_val == base_val:
            if in_ours:
                merged_fields[key] = copy.deepcopy(our_val)
                if our_val != base_val:
                    auto_resolved.append(
                        {
                            "field": key,
                            "resolution": "ours",
                            "reason": "only ours changed",
                        }
                    )
            else:
                # We removed it
                auto_resolved.append(
                    {"field": key, "resolution": "ours", "reason": "removed by ours"}
                )
            continue

        # Only theirs changed
        if their_val != base_val and our_val == base_val:
            if in_theirs:
                merged_fields[key] = copy.deepcopy(their_val)
                if their_val != base_val:
                    auto_resolved.append(
                        {
                            "field": key,
                            "resolution": "theirs",
                            "reason": "only theirs changed",
                        }
                    )
            else:
                # They removed it
                auto_resolved.append(
                    {
                        "field": key,
                        "resolution": "theirs",
                        "reason": "removed by theirs",
                    }
                )
            continue

        # Both changed the same way
        if our_val == their_val:
            if in_ours:
                merged_fields[key] = copy.deepcopy(our_val)
            auto_resolved.append(
                {"field": key, "resolution": "both", "reason": "identical changes"}
            )
            continue

        # Both changed differently → conflict
        conflicts.append(
            {
                "field": key,
                "base": base_val,
                "ours": our_val,
                "theirs": their_val,
            }
        )

    # Build merged content
    merged_version = ours.get(
        "version", theirs.get("version", base.get("version", "0.0.0"))
    )

    if conflicts:
        return OntologyMergeResult(
            merged=None,
            conflicts=conflicts,
            auto_resolved=auto_resolved,
        )

    merged = {
        "version": merged_version,
        "fields": merged_fields,
    }

    return OntologyMergeResult(
        merged=merged,
        conflicts=[],
        auto_resolved=auto_resolved,
    )
