"""mycelium.py
==============

מצע קוגניטיבי אחסוני תואם-LLM.
"""

import zlib
import marshal
import hashlib as hs
from pathlib import Path
from typing import Any, Iterable, List, Set, Tuple

# ============================================================
# שורש אחסון
# ============================================================


def קבל_שורש_אחסון(שם_מופע: str) -> Path:
    """
    מחזיר שורש אחסון למופע ספציפי.
    יוצר תיקייה לפי גיבוב שם המופע לצורך בידוד.
    """
    בסיס = Path(__file__).resolve().parent.parent / "Mycelium"

    if שם_מופע:
        גיבוב = hs.sha1(שם_מופע.encode()).hexdigest()[:16]
        שורש_מופע = בסיס / גיבוב
    else:
        שורש_מופע = בסיס / "default"

    שורש_מופע.mkdir(parents=True, exist_ok=True)
    return שורש_מופע


# ============================================================
# הפלואיד - זיכרון אטומי
# ============================================================


class הפלואיד:
    """
    זיכרון מתמיד נגיש-אינדקס.
    """

    __slots__ = ("שם", "נתיב", "_נתונים", "_חלל", "שורש_אחסון")

    def __init__(self, שם: str, שורש_אחסון: Path = None):
        self.שם = שם
        self.שורש_אחסון = שורש_אחסון or קבל_שורש_אחסון(None)

        מזהה = hs.sha1(שם.encode()).hexdigest()
        self.נתיב = self.שורש_אחסון / f"{מזהה}.hx"

        self._נתונים: List[Any] = []
        self._חלל: List[int] = []

        self._טען()

    # --- תאימות מאפיינים באנגלית ---

    @property
    def name(self) -> str:
        return self.שם

    @name.setter
    def name(self, value: str):
        self.שם = value

    @property
    def path(self) -> Path:
        return self.נתיב

    @path.setter
    def path(self, value: Path):
        self.נתיב = value

    @property
    def storage_root(self) -> Path:
        return self.שורש_אחסון

    @storage_root.setter
    def storage_root(self, value: Path):
        self.שורש_אחסון = value

    # ---------------- התמדה ----------------

    def _טען(self):
        if not self.נתיב.exists():
            return
        try:
            גולמי = zlib.decompress(self.נתיב.read_bytes())
            self._נתונים, self._חלל = marshal.loads(גולמי)
        except Exception:
            self._נתונים, self._חלל = [], []

    def _התחייב(self):
        מטען = marshal.dumps((self._נתונים, self._חלל))
        self.נתיב.write_bytes(zlib.compress(מטען, 9))

    # ---------------- פעולות ליבה ----------------

    def הקצה(self, ערך: Any) -> int:
        if self._חלל:
            אינדקס = self._חלל.pop()
            self._נתונים[אינדקס] = ערך
        else:
            אינדקס = len(self._נתונים)
            self._נתונים.append(ערך)
        self._התחייב()
        return אינדקס

    def קרא(self, אינדקס: int) -> Any:
        return self._נתונים[אינדקס]

    def כתוב(self, אינדקס: int, ערך: Any):
        self._נתונים[אינדקס] = ערך
        self._התחייב()

    def מחק(self, אינדקס: int):
        self._נתונים[אינדקס] = None
        self._חלל.append(אינדקס)
        self._התחייב()

    # ---------------- פעולות מרובות ----------------

    def קריאה_מרובה(self, אינדקסים: Iterable[int]) -> List[Any]:
        return [self._נתונים[i] for i in אינדקסים]

    def כתיבה_מרובה(self, זוגות: Iterable[Tuple[int, Any]]):
        for אינדקס, ערך in זוגות:
            self._נתונים[אינדקס] = ערך
        self._התחייב()

    # ---------------- אינטרוספקטציה ----------------

    def גודל(self) -> int:
        return len(self._נתונים)

    def פעילים(self) -> int:
        return len(self._נתונים) - len(self._חלל)

    def פנוי(self) -> int:
        return len(self._חלל)

    # --- תאימות שיטות באנגלית ---
    alloc = הקצה
    read = קרא
    write = כתוב
    delete = מחק
    bulk_read = קריאה_מרובה
    bulk_write = כתיבה_מרובה
    size = גודל
    active = פעילים
    free = פנוי


# ============================================================
# דיפלואיד - גרף יחסים
# ============================================================


class דיפלואיד:
    """
    גרף יחסים מתמיד:
        (subject, relation, object)
    """

    def __init__(self, שם: str, שורש_אחסון: Path = None):
        self.שורש_אחסון = שורש_אחסון or קבל_שורש_אחסון(None)
        self.שלשות = הפלואיד(f"{שם}::triples", self.שורש_אחסון)
        self.קדימה = הפלואיד(f"{שם}::forward", self.שורש_אחסון)
        self.אחורה = הפלואיד(f"{שם}::backward", self.שורש_אחסון)

    # --- תאימות מאפיינים באנגלית ---

    @property
    def storage_root(self) -> Path:
        return self.שורש_אחסון

    @storage_root.setter
    def storage_root(self, value: Path):
        self.שורש_אחסון = value

    @property
    def triples(self):
        return self.שלשות

    @property
    def forward(self):
        return self.קדימה

    @property
    def backward(self):
        return self.אחורה

    def קשר(self, נ: int, ר: int, מ: int) -> int:
        אינדקס = self.שלשות.הקצה((נ, ר, מ))
        self._צרף(self.קדימה, נ, אינדקס)
        self._צרף(self.אחורה, מ, אינדקס)
        return אינדקס

    def נתק(self, אינדקס: int):
        נ, _, מ = self.שלשות.קרא(אינדקס)
        self._הסר(self.קדימה, נ, אינדקס)
        self._הסר(self.אחורה, מ, אינדקס)
        self.שלשות.מחק(אינדקס)

    def יוצא(self, נ: int) -> List[int]:
        return self._קבל(self.קדימה, נ)

    def נכנס(self, מ: int) -> List[int]:
        return self._קבל(self.אחורה, מ)

    def פתר(self, אינדקס: int) -> Tuple[int, int, int]:
        return self.שלשות.קרא(אינדקס)

    # ---------- פנימי ----------

    def _צרף(self, תא: הפלואיד, מפתח: int, ערך: int):
        while מפתח >= תא.גודל():
            תא.הקצה([])
        דלי = תא.קרא(מפתח) or []
        דלי.append(ערך)
        תא.כתוב(מפתח, דלי)

    def _הסר(self, תא: הפלואיד, מפתח: int, ערך: int):
        try:
            דלי = תא.קרא(מפתח)
            if דלי:
                דלי.remove(ערך)
                תא.כתוב(מפתח, דלי)
        except Exception:
            pass

    def _קבל(self, תא: הפלואיד, מפתח: int) -> List[int]:
        try:
            return תא.קרא(מפתח) or []
        except Exception:
            return []

    # --- תאימות שיטות באנגלית ---
    link = קשר
    unlink = נתק
    outgoing = יוצא
    incoming = נכנס
    resolve = פתר


# ============================================================
# טריאדי - סריג אילוצים (קבוצות)
# ============================================================


class טריאדי:
    """
    מערכת אילוצים מבוססת צירים.
    """

    def __init__(self, שם: str, שורש_אחסון: Path = None):
        self.שורש_אחסון = שורש_אחסון or קבל_שורש_אחסון(None)
        self.צירים = הפלואיד(f"{שם}::axes", self.שורש_אחסון)

    # --- תאימות מאפיינים באנגלית ---

    @property
    def storage_root(self) -> Path:
        return self.שורש_אחסון

    @storage_root.setter
    def storage_root(self, value: Path):
        self.שורש_אחסון = value

    @property
    def axes(self):
        return self.צירים

    def צרף(self, ציר: int, עובדה_: int):
        קבוצת_ציר = self._קבל(ציר)
        קבוצת_ציר.add(עובדה_)
        self._קבע(ציר, קבוצת_ציר)

    def הסר(self, ציר: int, עובדה_: int):
        קבוצת_ציר = self._קבל(ציר)
        קבוצת_ציר.discard(עובדה_)
        self._קבע(ציר, קבוצת_ציר)

    def חיתוך(self, צירים: List[int]) -> Set[int]:
        if not צירים:
            return set()
        קבוצות = [self._קבל(צ) for צ in צירים]
        return set.intersection(*קבוצות)

    def איחוד(self, צירים: List[int]) -> Set[int]:
        return set.union(*(self._קבל(צ) for צ in צירים)) if צירים else set()

    def הפרש(self, בסיס: int, הסרה: List[int]) -> Set[int]:
        תוצאה = self._קבל(בסיס).copy()
        for צ in הסרה:
            תוצאה.difference_update(self._קבל(צ))
        return תוצאה

    # ---------- פנימי ----------

    def _קבל(self, אינדקס: int) -> Set[int]:
        try:
            קבוצת_ציר = self.צירים.קרא(אינדקס)
            return קבוצת_ציר if isinstance(קבוצת_ציר, set) else set()
        except Exception:
            return set()

    def _קבע(self, אינדקס: int, קבוצת_ציר: Set[int]):
        while אינדקס >= self.צירים.גודל():
            self.צירים.הקצה(set())
        self.צירים.כתוב(אינדקס, קבוצת_ציר)

    # --- תאימות שיטות באנגלית ---
    attach = צרף
    detach = הסר
    intersect = חיתוך
    union = איחוד
    difference = הפרש


# ============================================================
# פוליפלואיד - שדות מושגיים
# ============================================================


class פוליפלואיד:
    """
    שדות מושגיים המורכבים ממספר צירים.
    """

    def __init__(self, שם: str, טריאדי_: טריאדי, שורש_אחסון: Path = None):
        self.שורש_אחסון = שורש_אחסון or קבל_שורש_אחסון(None)
        self.מושגים = הפלואיד(f"{שם}::concepts", self.שורש_אחסון)
        self.טריאדי = טריאדי_

    # --- תאימות מאפיינים באנגלית ---

    @property
    def storage_root(self) -> Path:
        return self.שורש_אחסון

    @storage_root.setter
    def storage_root(self, value: Path):
        self.שורש_אחסון = value

    @property
    def concepts(self):
        return self.מושגים

    @property
    def triadic(self):
        return self.טריאדי

    def הגדר(self, מושג: int, צירים: Set[int]):
        while מושג >= self.מושגים.גודל():
            self.מושגים.הקצה(set())
        self.מושגים.כתוב(מושג, צירים)

    def פתר(self, מושג: int) -> Set[int]:
        צירים = self.מושגים.קרא(מושג)
        if not צירים:
            return set()
        return self.טריאדי.חיתוך(list(צירים))

    # --- תאימות שיטות באנגלית ---
    define = הגדר
    resolve = פתר


# ============================================================
# מיצליום - אורגניזם מאוחד
# ============================================================


class מיצליום:
    """
    מצע קוגניטיבי מאוחד עם אחסון לפי מופע.
    """

    _מופעים = {}
    _instances = _מופעים  # תאימות אנגלית

    @classmethod
    def קבל(cls, שם: str):
        if שם not in cls._מופעים:
            cls._מופעים[שם] = cls(שם)
        return cls._מופעים[שם]

    @classmethod
    def get(cls, name: str):
        return cls.קבל(name)

    def __init__(self, שם: str):
        self.שם = שם
        self.שורש_אחסון = קבל_שורש_אחסון(שם)
        self.name = self.שם
        self.storage_root = self.שורש_אחסון

        # רכיבים עם אחסון תלוי-מופע
        self.זיכרון = הפלואיד(f"{שם}::memory", self.שורש_אחסון)
        self.יחסים = דיפלואיד(שם, self.שורש_אחסון)
        self.מגבלות = טריאדי(שם, self.שורש_אחסון)
        self.מושגים = פוליפלואיד(שם, self.מגבלות, self.שורש_אחסון)

        # תאימות אנגלית
        self.memory = self.זיכרון
        self.relations = self.יחסים
        self.constraints = self.מגבלות
        self.concepts = self.מושגים

    # ---------- נוחות ----------

    def עובדה(self, ערך: Any) -> int:
        return self.זיכרון.הקצה(ערך)

    def fact(self, value: Any) -> int:
        return self.עובדה(value)

    def היזכר(self, אינדקס: int) -> Any:
        return self.זיכרון.קרא(אינדקס)

    def recall(self, idx: int) -> Any:
        return self.היזכר(idx)

    def קשר(self, נ: int, ר: int, מ: int) -> int:
        return self.יחסים.קשר(נ, ר, מ)

    def relate(self, s: int, r: int, o: int) -> int:
        return self.קשר(s, r, o)

    def תייג(self, ציר: int, עובדה_: int):
        self.מגבלות.צרף(ציר, עובדה_)

    def tag(self, axis: int, fact: int):
        return self.תייג(axis, fact)

    def הגדר_מושג(self, מושג: int, צירים: Set[int]):
        self.מושגים.הגדר(מושג, צירים)

    def define_concept(self, concept: int, axes: Set[int]):
        return self.הגדר_מושג(concept, axes)

    def פתר_מושג(self, מושג: int) -> Set[int]:
        return self.מושגים.פתר(מושג)

    def resolve_concept(self, concept: int) -> Set[int]:
        return self.פתר_מושג(concept)

    # ---------- מידע מופע ----------

    def קבל_מידע_אחסון(self) -> dict:
        return {
            "instance": self.שם,
            "storage_path": str(self.שורש_אחסון),
            "memory_size": self.זיכרון.גודל(),
            "memory_active": self.זיכרון.פעילים(),
            "memory_free": self.זיכרון.פנוי(),
        }

    def get_storage_info(self) -> dict:
        return self.קבל_מידע_אחסון()


# ============================================================
# יצוא מודול
# ============================================================

__all__ = [
    "הפלואיד",
    "דיפלואיד",
    "טריאדי",
    "פוליפלואיד",
    "מיצליום",
    "קבל_שורש_אחסון",
    "Haploid",
    "Diploid",
    "Triadic",
    "Polyploid",
    "Mycelium",
    "get_storage_root",
]

# תאימות שמות
Haploid = הפלואיד
Diploid = דיפלואיד
Triadic = טריאדי
Polyploid = פוליפלואיד
Mycelium = מיצליום
get_storage_root = קבל_שורש_אחסון
