"""L1 GEOMETRIC Layer

Navigate by file and folder hierarchy.
"""
from __future__ import annotations

from typing import List, Dict, Optional, Any
from pathlib import Path
import fnmatch

from .base import Layer, LayerID, Token


class L1_Geometric(Layer):
    """L1 GEOMETRIC: Navigate by file and folder hierarchy."""

    LAYER_ID = LayerID.GEOMETRIC
    LAYER_NAME = "GEOMETRIC"
    LAYER_DESCRIPTION = "Navigate by file and folder hierarchy"

    def query(self, pattern: str, limit: int = 100) -> List[Token]:
        """Query by path pattern (glob-like)."""
        results = []
        for token in self._memory._tokens.values():
            if token.path and fnmatch.fnmatch(token.path, pattern):
                results.append(token)
                if len(results) >= limit:
                    break
        return results

    def filter(self, tokens: List[Token], **criteria) -> List[Token]:
        """Filter by geometric criteria."""
        results = tokens

        if "depth" in criteria:
            target_depth = criteria["depth"]
            results = [t for t in results if t.path and len(Path(t.path).parts) == target_depth]

        if "extension" in criteria:
            ext = criteria["extension"]
            if not ext.startswith("."):
                ext = "." + ext
            results = [t for t in results if t.path and t.path.endswith(ext)]

        if "folder" in criteria:
            folder = criteria["folder"]
            results = [t for t in results if t.path and folder in str(Path(t.path).parent)]

        return results

    def navigate(self, token: Token, direction: str) -> Optional[Token]:
        """Navigate in geometric direction."""
        if not token.path:
            return None

        path = Path(token.path)

        if direction == "parent":
            parent_path = str(path.parent)
            for t in self._memory._tokens.values():
                if t.path == parent_path:
                    return t
            return Token.from_path(parent_path)

        elif direction == "first_child":
            children = self.children(token)
            return children[0] if children else None

        elif direction == "next_sibling":
            siblings = self.siblings(token)
            try:
                idx = siblings.index(token)
                return siblings[idx + 1] if idx < len(siblings) - 1 else None
            except (ValueError, IndexError):
                return None

        elif direction == "prev_sibling":
            siblings = self.siblings(token)
            try:
                idx = siblings.index(token)
                return siblings[idx - 1] if idx > 0 else None
            except (ValueError, IndexError):
                return None

        return None

    def distance(self, a: Token, b: Token) -> float:
        """Geometric distance: path edit distance."""
        if not a.path or not b.path:
            return float('inf')

        parts_a = Path(a.path).parts
        parts_b = Path(b.path).parts

        common = 0
        for pa, pb in zip(parts_a, parts_b):
            if pa == pb:
                common += 1
            else:
                break

        return (len(parts_a) - common) + (len(parts_b) - common)

    def parent(self, token: Token) -> Optional[Token]:
        """Get parent folder token."""
        return self.navigate(token, "parent")

    def children(self, token: Token) -> List[Token]:
        """Get all children (files in folder)."""
        if not token.path:
            return []

        parent_path = token.path
        children = []
        for t in self._memory._tokens.values():
            if t.path and t.path != parent_path:
                if str(Path(t.path).parent) == parent_path:
                    children.append(t)

        return sorted(children, key=lambda t: t.path or "")

    def siblings(self, token: Token) -> List[Token]:
        """Get sibling tokens (same folder)."""
        if not token.path:
            return []

        parent_path = str(Path(token.path).parent)
        siblings = []
        for t in self._memory._tokens.values():
            if t.path and str(Path(t.path).parent) == parent_path:
                siblings.append(t)

        return sorted(siblings, key=lambda t: t.path or "")

    def depth(self, token: Token) -> int:
        """Get path depth of token."""
        if not token.path:
            return 0
        return len(Path(token.path).parts)
