"""Core data models for the knowledge graph."""

from __future__ import annotations

from collections import Counter
from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path


class NodeType(str, Enum):
    FILE = "File"
    FOLDER = "Folder"
    FUNCTION = "Function"
    CLASS = "Class"
    METHOD = "Method"
    VARIABLE = "Variable"
    IMPORT = "Import"
    CLUSTER = "Cluster"
    PROCESS = "Process"


class EdgeType(str, Enum):
    CONTAINS = "CONTAINS"           # Folder -> File, File -> Function/Class
    CALLS = "CALLS"                 # Function -> Function
    IMPORTS = "IMPORTS"             # File -> File
    EXTENDS = "EXTENDS"             # Class -> Class
    IMPLEMENTS = "IMPLEMENTS"       # Class -> Interface
    HAS_METHOD = "HAS_METHOD"       # Class -> Method
    HAS_PROPERTY = "HAS_PROPERTY"   # Class -> Variable
    DEFINED_IN = "DEFINED_IN"       # Function/Class -> File


@dataclass
class SymbolNode:
    """A node in the knowledge graph representing a code symbol."""
    uid: str                        # Unique ID: file_path:name:line
    name: str
    node_type: NodeType
    file_path: str
    line_start: int
    line_end: int
    language: str = ""
    docstring: str = ""
    signature: str = ""             # Function signature or class definition
    body_text: str = ""             # Raw source text of the symbol
    properties: dict = field(default_factory=dict)

    @staticmethod
    def make_uid(file_path: str, name: str, line: int) -> str:
        return f"{file_path}:{name}:{line}"


@dataclass
class Edge:
    """A relationship between two nodes."""
    source_uid: str
    target_uid: str
    edge_type: EdgeType
    properties: dict = field(default_factory=dict)


@dataclass
class FileNode:
    """Represents a source file."""
    path: str
    relative_path: str
    language: str
    size_bytes: int
    symbols: list[SymbolNode] = field(default_factory=list)
    imports: list[str] = field(default_factory=list)
    source_text: str = ""  # Cached source for resolver (avoids re-reading from disk)


@dataclass
class ProjectIndex:
    """Complete index of a project."""
    root_path: str
    files: list[FileNode] = field(default_factory=list)
    nodes: list[SymbolNode] = field(default_factory=list)
    edges: list[Edge] = field(default_factory=list)

    @property
    def stats(self) -> dict:
        type_counts = Counter(n.node_type.value for n in self.nodes)
        edge_counts = Counter(e.edge_type.value for e in self.edges)
        return {
            "files": len(self.files),
            "nodes": len(self.nodes),
            "edges": len(self.edges),
            "node_types": dict(type_counts),
            "edge_types": dict(edge_counts),
        }
