# acl/repository/jpa_acl_repository.py
from typing import Any, Dict, List, Optional, Type
from sqlalchemy import text
from sqlalchemy.orm import Session

from acl.models.acl_entity import ACLEntity  # example import if needed
from acl.models.datasource_mapping import EntityDatasourceMapping
from acl.repository.interface import DynamicAclRepository


class JpaAclRepositoryImpl(DynamicAclRepository):
    """
    SQL/Native implementation for ACL filtering
    """

    def _get_group_mapping(self, db: Session, current_user: str, account_id: str) -> List[str]:
        stmt = text("""
            SELECT DISTINCT t.entity_id
            FROM acl_entities t
            JOIN aclentity_memberships am ON am.aclentity_id = t.id
            JOIN ikon_groups g ON g.id = am.group_id
            JOIN ikon_group_memberships gm ON gm.group_id = g.id
            WHERE gm.user_id = :current_user AND gm.account_id = :account_id
        """)
        rows = db.execute(stmt, {"current_user": current_user, "account_id": account_id}).all()
        return [row[0] for row in rows]

    def _get_account_mapping(self, db: Session, account_id: str) -> List[str]:
        stmt = text("""
            SELECT DISTINCT t.entity_id
            FROM acl_entities t
            WHERE t.account_id = :account_id
        """)
        rows = db.execute(stmt, {"account_id": account_id}).all()
        return [row[0] for row in rows]

    def _get_user_mapping(self, db: Session, current_user: str) -> List[str]:
        stmt = text("""
            SELECT DISTINCT t.entity_id
            FROM acl_entities t
            WHERE t.user_id = :current_user
        """)
        rows = db.execute(stmt, {"current_user": current_user}).all()
        return [row[0] for row in rows]

    def get_entities(
        self,
        db: Session,
        entity_class: Type[Any],
        entity_table_name: str,
        sql_query: Optional[str],
        filters: Optional[Dict[str, Any]],
        pagination: Optional[Dict[str, int]],
        current_user: str,
        account_id: str,
    ) -> List[Any]:

        sql = f"SELECT * FROM ({sql_query}) e" if sql_query else f"SELECT * FROM {entity_table_name} e"
        where_clauses = []

        # ACL Filtering Logic
        groups = self._get_group_mapping(db, current_user, account_id)
        accounts = self._get_account_mapping(db, account_id)
        users = self._get_user_mapping(db, current_user)

        if not groups and not users:
            return []

        acl_clauses = []
        if groups: acl_clauses.append("e.id IN (:groups)")
        if accounts: acl_clauses.append("e.id IN (:accounts)")
        if users: acl_clauses.append("e.id IN (:users)")

        where_clauses.append(" AND ".join(acl_clauses))

        # Apply filters
        params: Dict[str, Any] = {}
        if filters:
            filter_parts = []
            for key, value in filters.items():
                filter_parts.append(f"e.{key} = :{key}")
                params[key] = value
            where_clauses.append(" AND ".join(filter_parts))

        if where_clauses:
            sql += " WHERE " + " AND ".join(f"({wc})" for wc in where_clauses)

        print("Generated SQL:", sql)

        query = text(sql)
        if groups: params["groups"] = tuple(groups)
        if accounts: params["accounts"] = tuple(accounts)
        if users: params["users"] = tuple(users)

        page = pagination.get("page", 1) if pagination else 1
        size = pagination.get("size", 20) if pagination else 20
        offset = (page - 1) * size

        rows = db.execute(query, params).fetchall()
        ids = [row.id for row in rows[offset : offset + size]]
        if not ids:
            return []

        return db.query(entity_class).filter(entity_class.id.in_(ids)).all()
