"""
Shared Library deletion cascade.

Deletes a Library node and everything reachable AND unique to it
(Collections, Items, Chunks, Images + ImageEmbeddings), then garbage-collects
Concepts that are no longer referenced by any other Library.

Keyed on the Library ``uid`` so it works for *both* global libraries
(``workspace_id`` is null) and workspace-scoped libraries. This is the single
source of truth used by:

  * the Daedalus integration API (``DELETE /library/api/workspaces/{id}/``), and
  * the admin/HTML delete view (``library_delete``).

Concept-safe: orphan-only Concept GC happens at the end. Concepts still
referenced by another library (workspace or global) are preserved.
"""

import logging

from neomodel import db

logger = logging.getLogger(__name__)


def delete_library_cascade(lib) -> dict:
    """Delete ``lib`` and all content reachable and unique to it.

    :param lib: A ``library.models.Library`` node instance.
    :returns: Dict with ``library_uid``, ``name``, ``item_count``,
        ``item_s3_keys`` (list of ``(uid, s3_key)`` for async S3 cleanup),
        and ``orphans_deleted`` (Concept GC count).
    """
    library_uid = lib.uid
    library_name = lib.name

    # Collect Item s3_keys first so the caller can clean up S3 asynchronously
    # (a future enhancement — for now, the keys are returned/logged).
    s3_rows, _ = db.cypher_query(
        "MATCH (l:Library {uid: $uid})-[:CONTAINS]->(:Collection)"
        "-[:CONTAINS]->(i:Item) RETURN i.uid, i.s3_key",
        {"uid": library_uid},
    )
    item_s3_keys = [(r[0], r[1]) for r in s3_rows if r[1]]

    db.cypher_query(
        """
        MATCH (l:Library {uid: $uid})-[:CONTAINS]->(:Collection)
        -[:CONTAINS]->(i:Item)-[:HAS_CHUNK]->(c:Chunk)
        DETACH DELETE c
        """,
        {"uid": library_uid},
    )
    db.cypher_query(
        """
        MATCH (l:Library {uid: $uid})-[:CONTAINS]->(:Collection)
        -[:CONTAINS]->(i:Item)-[:HAS_IMAGE]->(img:Image)
        OPTIONAL MATCH (img)-[:HAS_EMBEDDING]->(emb:ImageEmbedding)
        DETACH DELETE img, emb
        """,
        {"uid": library_uid},
    )
    db.cypher_query(
        """
        MATCH (l:Library {uid: $uid})-[:CONTAINS]->(:Collection)
        -[:CONTAINS]->(i:Item)
        DETACH DELETE i
        """,
        {"uid": library_uid},
    )
    db.cypher_query(
        """
        MATCH (l:Library {uid: $uid})-[:CONTAINS]->(col:Collection)
        DETACH DELETE col
        """,
        {"uid": library_uid},
    )
    db.cypher_query(
        "MATCH (l:Library {uid: $uid}) DETACH DELETE l",
        {"uid": library_uid},
    )

    # Orphan Concept garbage collection: drop Concepts no longer referenced
    # by any Item (REFERENCES/MENTIONS) or Image (DEPICTS).
    orphan_result, _ = db.cypher_query(
        """
        MATCH (con:Concept)
        WHERE NOT (con)<-[:REFERENCES]-() AND NOT (con)<-[:MENTIONS]-()
              AND NOT (con)<-[:DEPICTS]-()
        WITH con
        DETACH DELETE con
        RETURN count(con) AS deleted
        """
    )
    orphans_deleted = orphan_result[0][0] if orphan_result else 0

    logger.info(
        "Library cascade-deleted library_uid=%s name=%s items=%d orphans_deleted=%d",
        library_uid, library_name, len(item_s3_keys), orphans_deleted,
    )

    return {
        "library_uid": library_uid,
        "name": library_name,
        "item_count": len(item_s3_keys),
        "item_s3_keys": item_s3_keys,
        "orphans_deleted": orphans_deleted,
    }


def delete_collection_cascade(col) -> dict:
    """Delete ``col`` and all content reachable and unique to it.

    Removes the Collection's Items with their Chunks, Images, and
    ImageEmbeddings, then the Collection itself. No orphan-Concept GC —
    that invariant belongs to library-level deletes only (see
    :func:`delete_library_cascade`); Concepts orphaned here are collected
    on the next library delete.

    :param col: A ``library.models.Collection`` node instance.
    :returns: Dict with ``collection_uid``, ``name``, ``item_count``, and
        ``item_s3_keys`` (list of ``(uid, s3_key)`` for async S3 cleanup).
    """
    collection_uid = col.uid
    collection_name = col.name

    s3_rows, _ = db.cypher_query(
        "MATCH (col:Collection {uid: $uid})-[:CONTAINS]->(i:Item) "
        "RETURN i.uid, i.s3_key",
        {"uid": collection_uid},
    )
    item_s3_keys = [(r[0], r[1]) for r in s3_rows if r[1]]

    db.cypher_query(
        """
        MATCH (col:Collection {uid: $uid})-[:CONTAINS]->(i:Item)
        -[:HAS_CHUNK]->(c:Chunk)
        DETACH DELETE c
        """,
        {"uid": collection_uid},
    )
    db.cypher_query(
        """
        MATCH (col:Collection {uid: $uid})-[:CONTAINS]->(i:Item)
        -[:HAS_IMAGE]->(img:Image)
        OPTIONAL MATCH (img)-[:HAS_EMBEDDING]->(emb:ImageEmbedding)
        DETACH DELETE img, emb
        """,
        {"uid": collection_uid},
    )
    db.cypher_query(
        """
        MATCH (col:Collection {uid: $uid})-[:CONTAINS]->(i:Item)
        DETACH DELETE i
        """,
        {"uid": collection_uid},
    )
    db.cypher_query(
        "MATCH (col:Collection {uid: $uid}) DETACH DELETE col",
        {"uid": collection_uid},
    )

    logger.info(
        "Collection cascade-deleted collection_uid=%s name=%s items=%d",
        collection_uid, collection_name, len(item_s3_keys),
    )

    return {
        "collection_uid": collection_uid,
        "name": collection_name,
        "item_count": len(item_s3_keys),
        "item_s3_keys": item_s3_keys,
    }


def delete_item_cascade(item_uid: str) -> dict:
    """Delete the Item ``item_uid`` with its Chunks, Images, and embeddings.

    Keyed on the uid (not a node instance) so the ingest supersede path in
    ``library.tasks`` can share it. No orphan-Concept GC — see
    :func:`delete_collection_cascade`.

    :returns: Dict with ``item_uid`` and ``s3_key`` (empty string when the
        item had no stored file) for async S3 cleanup.
    """
    s3_rows, _ = db.cypher_query(
        "MATCH (i:Item {uid: $uid}) RETURN i.s3_key",
        {"uid": item_uid},
    )
    s3_key = (s3_rows[0][0] or "") if s3_rows else ""

    db.cypher_query(
        """
        MATCH (i:Item {uid: $uid})
        OPTIONAL MATCH (i)-[:HAS_CHUNK]->(c:Chunk)
        OPTIONAL MATCH (i)-[:HAS_IMAGE]->(img:Image)
        OPTIONAL MATCH (img)-[:HAS_EMBEDDING]->(emb:ImageEmbedding)
        DETACH DELETE c, img, emb, i
        """,
        {"uid": item_uid},
    )

    logger.info("Item cascade-deleted item_uid=%s", item_uid)
    return {"item_uid": item_uid, "s3_key": s3_key}
