"""
Lineage Tracker - Track data lineage through field relationships.

Traverses the field relationship graph to find upstream and
downstream dependencies.
"""

from __future__ import annotations

from typing import Any

from pycharter.wiki.shared.errors import GraphError


class LineageTracker:
    """
    Tracks data lineage through field relationships.

    Args:
        session: SQLAlchemy session
    """

    def __init__(self, session=None):
        self._session = session

    def _require_session(self):
        if self._session is None:
            raise GraphError("No database session configured")

    _DEFAULT_UPSTREAM_TYPES = ("derived_from", "references", "depends_on")

    def get_upstream(
        self,
        field_id: str,
        relationship_types: list[str] | None = None,
    ) -> list[dict[str, Any]]:
        """
        Get upstream fields (fields this field depends on).

        Args:
            field_id: UUID of the field.
            relationship_types: Types to follow. Defaults to
                ``derived_from``, ``references``, ``depends_on``.

        Returns:
            List of upstream field dicts.
        """
        self._require_session()
        types = tuple(relationship_types or self._DEFAULT_UPSTREAM_TYPES)

        from sqlalchemy import text

        # Build IN clause with bind params
        placeholders = ", ".join(f":t{i}" for i in range(len(types)))
        params: dict[str, Any] = {"field_id": field_id}
        params.update({f"t{i}": t for i, t in enumerate(types)})

        query = text(f"""
            WITH RECURSIVE upstream AS (
                SELECT fr.source_field_id, fr.target_field_id, fr.relationship_type, 1 as depth
                FROM pycharter.field_relationships fr
                WHERE fr.source_field_id = :field_id
                  AND fr.relationship_type IN ({placeholders})
                UNION ALL
                SELECT fr.source_field_id, fr.target_field_id, fr.relationship_type, u.depth + 1
                FROM pycharter.field_relationships fr
                JOIN upstream u ON fr.source_field_id = u.target_field_id
                WHERE fr.relationship_type IN ({placeholders})
                  AND u.depth < 10
            )
            SELECT DISTINCT f.id, f.contract_id, f.name, f.data_type, u.depth
            FROM upstream u
            JOIN pycharter.fields f ON f.id = u.target_field_id
            ORDER BY u.depth
        """)

        result = self._session.execute(query, params)
        return [
            {
                "id": str(row.id),
                "contract_id": row.contract_id,
                "name": row.name,
                "data_type": row.data_type,
                "depth": row.depth,
            }
            for row in result
        ]

    def get_downstream(
        self,
        field_id: str,
        relationship_types: list[str] | None = None,
    ) -> list[dict[str, Any]]:
        """
        Get downstream fields (fields that depend on this field).

        Args:
            field_id: UUID of the field.
            relationship_types: Types to follow. Defaults to
                ``derived_from``, ``references``, ``depends_on``.

        Returns:
            List of downstream field dicts.
        """
        self._require_session()
        types = tuple(relationship_types or self._DEFAULT_UPSTREAM_TYPES)

        from sqlalchemy import text

        placeholders = ", ".join(f":t{i}" for i in range(len(types)))
        params: dict[str, Any] = {"field_id": field_id}
        params.update({f"t{i}": t for i, t in enumerate(types)})

        query = text(f"""
            WITH RECURSIVE downstream AS (
                SELECT fr.source_field_id, fr.target_field_id, fr.relationship_type, 1 as depth
                FROM pycharter.field_relationships fr
                WHERE fr.target_field_id = :field_id
                  AND fr.relationship_type IN ({placeholders})
                UNION ALL
                SELECT fr.source_field_id, fr.target_field_id, fr.relationship_type, d.depth + 1
                FROM pycharter.field_relationships fr
                JOIN downstream d ON fr.target_field_id = d.source_field_id
                WHERE fr.relationship_type IN ({placeholders})
                  AND d.depth < 10
            )
            SELECT DISTINCT f.id, f.contract_id, f.name, f.data_type, d.depth
            FROM downstream d
            JOIN pycharter.fields f ON f.id = d.source_field_id
            ORDER BY d.depth
        """)

        result = self._session.execute(query, params)
        return [
            {
                "id": str(row.id),
                "contract_id": row.contract_id,
                "name": row.name,
                "data_type": row.data_type,
                "depth": row.depth,
            }
            for row in result
        ]

    def get_lineage_path(
        self, source_field_id: str, target_field_id: str
    ) -> list[dict[str, Any]]:
        """
        Get the lineage path between two fields.

        Args:
            source_field_id: Starting field UUID
            target_field_id: Ending field UUID

        Returns:
            Ordered list of fields along the path, or empty if no path
        """
        self._require_session()

        from sqlalchemy import text

        query = text("""
            WITH RECURSIVE path AS (
                SELECT fr.source_field_id, fr.target_field_id,
                       ARRAY[fr.source_field_id] as visited, 1 as depth
                FROM pycharter.field_relationships fr
                WHERE fr.source_field_id = :source_id
                UNION ALL
                SELECT fr.source_field_id, fr.target_field_id,
                       p.visited || fr.source_field_id, p.depth + 1
                FROM pycharter.field_relationships fr
                JOIN path p ON fr.source_field_id = p.target_field_id
                WHERE NOT fr.source_field_id = ANY(p.visited)
                  AND p.depth < 10
            )
            SELECT f.id, f.contract_id, f.name, f.data_type
            FROM path p
            JOIN pycharter.fields f ON f.id = p.target_field_id
            WHERE p.target_field_id = :target_id
            LIMIT 1
        """)

        result = self._session.execute(
            query, {"source_id": source_field_id, "target_id": target_field_id}
        )
        return [
            {
                "id": str(row.id),
                "contract_id": row.contract_id,
                "name": row.name,
                "data_type": row.data_type,
            }
            for row in result
        ]
