"""Entity and relation helper functions for Knowledge Graph.

Provides deterministic ID generation, predicate normalization,
and entity/edge data construction utilities.
"""
from __future__ import annotations

import hashlib
import re
from datetime import datetime, timezone
from typing import Any

from trustmem.ztm.constants import DEFAULT_CONFIDENCE

# Mention threshold for confidence promotion
MENTION_CONFIDENCE_PROMOTE_THRESHOLD = 3


# ============================================================
# Deterministic ID generation (content-addressable)
# ============================================================

def compute_entity_id(name: str, entity_type: str, user_id: str | None = None) -> str:
    """Generate deterministic entity ID from name + type + user_id.

    Same philosophy as Git's content-addressable storage:
    identical entities always produce the same ID.
    Uses "__null__" for NULL user_id to ensure stable hashing.
    """
    normalized_name = name.strip().lower()
    uid = user_id if user_id is not None else "__null__"
    data = f"{normalized_name}|{entity_type}|{uid}"
    return "ent_" + hashlib.sha256(data.encode()).hexdigest()[:40]


def compute_edge_id(subject_id: str, predicate: str, object_id: str) -> str:
    """Generate deterministic edge ID from subject + predicate + object.

    Prevents duplicate triples from being stored.
    """
    normalized_pred = normalize_predicate(predicate)
    data = f"{subject_id}|{normalized_pred}|{object_id}"
    return "edge_" + hashlib.sha256(data.encode()).hexdigest()[:40]


# ============================================================
# Predicate normalization
# ============================================================

def normalize_predicate(predicate: str) -> str:
    """Normalize predicate for consistent storage.

    - Lowercase
    - Spaces/hyphens → underscores
    - Remove consecutive underscores
    - Preserve Japanese characters
    """
    pred = predicate.strip().lower()
    pred = re.sub(r"[\s\-]+", "_", pred)
    pred = re.sub(r"_+", "_", pred)
    return pred.strip("_")


# ============================================================
# Valid entity types
# ============================================================

VALID_ENTITY_TYPES = {
    "person", "organization", "location", "product",
    "concept", "event", "other",
}


# ============================================================
# Confidence determination for entities
# ============================================================

def determine_entity_confidence(mention_count: int) -> str:
    """Determine confidence from mention_count.

    Entities start at "medium" and promote to "high" after enough mentions.
    """
    if mention_count >= MENTION_CONFIDENCE_PROMOTE_THRESHOLD:
        return "high"
    return DEFAULT_CONFIDENCE  # "medium"


# ============================================================
# Entity/Edge data builders
# ============================================================

def build_entity_node(
    name: str,
    entity_type: str,
    user_id: str | None = None,
    source_memory_id: str | None = None,
    metadata: dict | None = None,
) -> dict:
    """Build a new entity_node dict."""
    entity_id = compute_entity_id(name, entity_type, user_id)
    now = datetime.now(timezone.utc).isoformat()
    return {
        "entity_id": entity_id,
        "name": name.strip(),
        "entity_type": entity_type if entity_type in VALID_ENTITY_TYPES else "other",
        "user_id": user_id,
        "confidence": DEFAULT_CONFIDENCE,
        "source_memory_id": source_memory_id,
        "mention_count": 1,
        "metadata": metadata or {},
        "is_active": True,
        "created_at": now,
        "updated_at": now,
    }


def build_entity_edge(
    subject_id: str,
    subject_name: str,
    predicate: str,
    object_id: str,
    object_name: str,
    user_id: str | None = None,
    source_memory_id: str | None = None,
    metadata: dict | None = None,
) -> dict:
    """Build a new entity_edge dict."""
    normalized_pred = normalize_predicate(predicate)
    edge_id = compute_edge_id(subject_id, normalized_pred, object_id)
    now = datetime.now(timezone.utc).isoformat()
    return {
        "edge_id": edge_id,
        "subject_id": subject_id,
        "subject_name": subject_name.strip(),
        "predicate": normalized_pred,
        "object_id": object_id,
        "object_name": object_name.strip(),
        "user_id": user_id,
        "confidence": DEFAULT_CONFIDENCE,
        "source_memory_id": source_memory_id,
        "mention_count": 1,
        "metadata": metadata or {},
        "is_active": True,
        "created_at": now,
        "updated_at": now,
    }
