from __future__ import annotations

from dataclasses import dataclass


@dataclass
class ClientAccessScope:
    tenant_id: int
    branch_id: int | None
    allow_cross_branch: bool
    allow_cross_tenant: bool
    allow_all_clients: bool
    own_only: bool
    locked_partner_id: int | None
    can_assign_partner: bool
    can_change_branch: bool
    can_change_tenant: bool


def build_scope(request, user, permission_checker):
    active_tenant_id = int(request.session.get("active_tenant_id") or user.tenant_id)
    active_branch_value = request.session.get("active_branch_id")
    active_branch_id = None if active_branch_value in (None, "", 0, "0") else int(active_branch_value)

    allow_cross_branch = permission_checker("clients.cross_branch")
    allow_cross_tenant = permission_checker("clients.cross_tenant")
    can_assign_partner = permission_checker("clients.assign_partner")
    own_only = permission_checker("clients.view.own_only")

    allow_all_clients = bool((allow_cross_tenant and allow_cross_branch and not own_only) or permission_checker("clients.view.all"))

    locked_partner_id = user.id if own_only else None
    can_change_branch = allow_cross_branch
    can_change_tenant = allow_cross_tenant

    return ClientAccessScope(
        tenant_id=active_tenant_id,
        branch_id=active_branch_id or getattr(user, "branch_id", None),
        allow_cross_branch=allow_cross_branch,
        allow_cross_tenant=allow_cross_tenant,
        allow_all_clients=allow_all_clients,
        own_only=own_only,
        locked_partner_id=locked_partner_id,
        can_assign_partner=can_assign_partner,
        can_change_branch=can_change_branch,
        can_change_tenant=can_change_tenant,
    )



def is_partner_role(role_names) -> bool:
    names = {str(name).strip().lower() for name in (role_names or [])}
    return "partner" in names and "firm admin" not in names and "system admin" not in names


def enforce_partner_scope(scope: ClientAccessScope, *, user, role_names) -> ClientAccessScope:
    if is_partner_role(role_names):
        scope.allow_all_clients = False
        scope.own_only = True
        scope.locked_partner_id = int(user.id)
        scope.can_assign_partner = False
    return scope


def effective_partner_id(row: dict):
    return row.get("assoc_partner_user_id") or row.get("partner_id")


def effective_tenant_id(row: dict):
    return row.get("assoc_firm_tenant_id") or row.get("tenant_id")


def effective_branch_id(row: dict):
    return row.get("branch_id")


def can_view_client_row(scope: ClientAccessScope, row: dict, *, user_id: int) -> bool:
    if scope.allow_all_clients:
        return True

    if not scope.allow_cross_tenant and effective_tenant_id(row) != scope.tenant_id:
        return False

    branch_id = effective_branch_id(row)
    if not scope.allow_cross_branch and scope.branch_id and branch_id and branch_id != scope.branch_id:
        return False

    if scope.own_only and scope.locked_partner_id and effective_partner_id(row) != scope.locked_partner_id:
        return bool(row.get("has_review_access"))

    return True
