from typing import Dict, Optional

from backend.config import get_enterprise_agents
from backend.database import crud
from backend.utils.general_utils import _has_unpublished_changes


# --- Dashboard analytics ---
class AnalyticsService:
    def __init__(self, user: str):
        self._user = user

    def analytics_counts(self, owner: str) -> dict[str, int]:
        agents = crud.get_agents_by_owner(owner)
        live = sum(1 for a in agents if bool(a.published_version))
        in_progress = sum(1 for a in agents if _has_unpublished_changes(a.model_dump()))
        return {"myAgents": len(agents), "live": live, "inProgress": in_progress}

    def analytics_counts_all_user_agents(self) -> dict[str, int]:
        """
        Same semantics as analytics_counts(owner) but across *all* user agents.
        Counts pure drafts correctly: inProgress = _has_unpublished_changes(agent) regardless of publish.
        """
        agents = crud.get_all_agents()
        live = sum(1 for a in agents if bool(a.published_version))
        in_progress = sum(1 for a in agents if _has_unpublished_changes(a.model_dump()))
        return {"myAgents": len(agents), "live": live, "inProgress": in_progress}

    def dashboard_tiles(
        self,
        start: Optional[str] = None,
        end: Optional[str] = None,
        *,
        is_project_admin: bool = False,
        agent_type: Optional[str] = None,  # "all" | "user" | "enterprise"
        owner_id: Optional[str] = None,
    ) -> dict:
        if not is_project_admin:
            counts = self.analytics_counts(self._user)
            return {
                **counts,
                "sharedUsersDistinct": crud.analytics_shared_users(self._user),
                "shared": crud.analytics_shared_agents(self._user),
            }

        # Effective agentType: if ownerId is provided, we force user-scope to “see like this owner”
        effective_type = "user" if owner_id else (agent_type or "all").lower()
        ent = get_enterprise_agents(self._user) or []
        ent_ids = [a.get("id") for a in ent if a.get("id")]

        if effective_type == "user":
            if owner_id:
                u_counts = self.analytics_counts(owner_id)
                return {
                    **u_counts,
                    "sharedUsersDistinct": crud.analytics_shared_users(owner_id),
                    "shared": crud.analytics_shared_agents(owner_id),
                    "typeBreakdown": {
                        "user": {
                            "count": u_counts["myAgents"],
                            "live": u_counts["live"],
                            "inProgress": u_counts["inProgress"],
                        },
                        "enterprise": {"count": 0},
                        "total": u_counts["myAgents"],
                    },
                }
            else:
                u_counts = self.analytics_counts_all_user_agents()
                return {
                    **u_counts,
                    "sharedUsersDistinct": crud.analytics_shared_users_for_all_user_agents(),
                    "shared": crud.analytics_shared_agents_for_all_user_agents(),
                    "typeBreakdown": {
                        "user": {
                            "count": u_counts["myAgents"],
                            "live": u_counts["live"],
                            "inProgress": u_counts["inProgress"],
                        },
                        "enterprise": {"count": 0},
                        "total": u_counts["myAgents"],
                    },
                }

        if effective_type == "enterprise":
            e_count = len(ent_ids)
            return {
                "myAgents": e_count,
                "live": e_count,  # treat configured enterprise agents as live
                "inProgress": 0,
                "sharedUsersDistinct": 0,  # shares only apply to user agents
                "shared": 0,
                "typeBreakdown": {
                    "user": {"count": 0, "live": 0, "inProgress": 0},
                    "enterprise": {"count": e_count},
                    "total": e_count,
                },
            }

        # effective_type == "all"
        u_counts = self.analytics_counts_all_user_agents()
        e_count = len(ent_ids)
        return {
            "myAgents": u_counts["myAgents"] + e_count,
            "live": u_counts["live"] + e_count,
            "inProgress": u_counts["inProgress"],
            "sharedUsersDistinct": crud.analytics_shared_users_for_all_user_agents(),
            "shared": crud.analytics_shared_agents_for_all_user_agents(),
            "typeBreakdown": {
                "user": {"count": u_counts["myAgents"], "live": u_counts["live"], "inProgress": u_counts["inProgress"]},
                "enterprise": {"count": e_count},
                "total": u_counts["myAgents"] + e_count,
            },
        }

    def dashboard_usage(
        self,
        start: Optional[str],
        end: Optional[str],
        bucket: str,
        agent_id: Optional[str] = None,
        *,
        is_project_admin: bool = False,
        agent_type: Optional[str] = None,
        owner_id: Optional[str] = None,
    ):
        if not is_project_admin:
            if agent_id:
                a = crud.get_agent(agent_id)
                if not a or a.owner != self._user:
                    return []
            return crud.analytics_usage_buckets(self._user, start, end, bucket or "week", agent_id)
        ent = get_enterprise_agents(self._user) or []
        ent_ids = [a.get("id") for a in ent if a.get("id")]
        # If ownerId is set, we “see like this owner” (user-only scope inside store via EXISTS).
        eff_type = "user" if owner_id else (agent_type or "all")
        return crud.analytics_usage_buckets(
            self._user,
            start,
            end,
            bucket or "week",
            agent_id,
            is_project_admin=True,
            agent_type=eff_type,
            owner_id=owner_id,
            enterprise_ids=ent_ids,
        )

    def dashboard_feedback(
        self,
        start: Optional[str],
        end: Optional[str],
        agent_id: Optional[str] = None,
        *,
        is_project_admin: bool = False,
        agent_type: Optional[str] = None,
        owner_id: Optional[str] = None,
    ):
        if not is_project_admin:
            if agent_id:
                a = crud.get_agent(agent_id)
                if not a or a.owner != self._user:
                    return {"positive": 0, "negative": 0, "none": 0}
            return crud.analytics_feedback_counts(self._user, start, end, agent_id)
        ent = get_enterprise_agents(self._user) or []
        ent_ids = [a.get("id") for a in ent if a.get("id")]
        eff_type = "user" if owner_id else (agent_type or "all")
        return crud.analytics_feedback_counts(
            self._user,
            start,
            end,
            agent_id,
            is_project_admin=True,
            agent_type=eff_type,
            owner_id=owner_id,
            enterprise_ids=ent_ids,
        )

    def dashboard_active_users(
        self,
        start: Optional[str],
        end: Optional[str],
        bucket: str,
        agent_id: Optional[str] = None,
        *,
        is_project_admin: bool = False,
        agent_type: Optional[str] = None,
        owner_id: Optional[str] = None,
    ):
        if not is_project_admin:
            if agent_id:
                a = crud.get_agent(agent_id)
                if not a or a.owner != self._user:
                    return []
            return crud.analytics_active_users_buckets(self._user, start, end, bucket or "week", agent_id)
        ent = get_enterprise_agents(self._user) or []
        ent_ids = [a.get("id") for a in ent if a.get("id")]
        eff_type = "user" if owner_id else (agent_type or "all")
        return crud.analytics_active_users_buckets(
            self._user,
            start,
            end,
            bucket or "week",
            agent_id,
            is_project_admin=True,
            agent_type=eff_type,
            owner_id=owner_id,
            enterprise_ids=ent_ids,
        )

    def dashboard_activity(
        self,
        start: Optional[str],
        end: Optional[str],
        agent_id: Optional[str] = None,
        limit: int = 50,
        offset: int = 0,
        *,
        q: Optional[str] = None,
        sort_by: Optional[str] = None,
        sort_dir: Optional[str] = None,
        group_by: Optional[str] = None,
        is_project_admin: bool = False,
        agent_type: Optional[str] = None,
        owner_id: Optional[str] = None,
    ):
        if not is_project_admin:
            if agent_id:
                a = crud.get_agent(agent_id)
                if not a or a.owner != self._user:
                    return {"rows": [], "total": 0}
            rows, total = crud.analytics_activity(
                self._user,
                start,
                end,
                agent_id,
                limit,
                offset,
                q=q,
                sort_by=sort_by,
                sort_dir=sort_dir,
                group_by=group_by,
            )
            return {"rows": rows, "total": total}

        ent = get_enterprise_agents(self._user) or []
        ent_ids = [a.get("id") for a in ent if a.get("id")]
        eff_type = "user" if owner_id else (agent_type or "all")
        rows, total = crud.analytics_activity(
            self._user,
            start,
            end,
            agent_id,
            limit,
            offset,
            is_project_admin=True,
            agent_type=eff_type,
            owner_id=owner_id,
            enterprise_ids=ent_ids,
            q=q,
            sort_by=sort_by,
            sort_dir=sort_dir,
            group_by=group_by,
        )
        id_to_name: Dict[str, str] = {a.id: a.name or a.id for a in (crud.get_all_agents() or [])}
        id_to_name.update({e["id"]: e.get("name", e["id"]) for e in ent if e.get("id")})
        for r in rows:
            aid = r.get("agentId")
            if aid and id_to_name.get(aid) and (r.get("agentName") in (None, "", aid)):
                r["agentName"] = id_to_name[aid]
        return {"rows": rows, "total": total}

    def my_agents_minimal(self, *, is_project_admin: bool = False, owner_id: Optional[str] = None):
        """
        Return owner’s agents for the agent-picker.
        Project owner may pass owner_id to list that owner’s agents.
        """
        target = self._user
        if is_project_admin and owner_id:
            target = owner_id
        return [{"id": a.id, "name": a.name} for a in crud.get_agents_by_owner(target)]
