"""Team member management — invite, list, remove, role changes.

Firestore path: ``customers/{customer_id}/members/{email_hash}``.
Doc ID = SHA-256(email.lower()) for deterministic dedup.
"""

from __future__ import annotations

import hashlib
import logging
from datetime import UTC, datetime
from typing import Any

from backend.dashboard.context import MemberInfo

_log = logging.getLogger(__name__)


def _email_hash(email: str) -> str:
    """Deterministic doc ID from lowercase email."""
    return hashlib.sha256(email.lower().encode()).hexdigest()


async def list_members(customer_id: str) -> list[MemberInfo]:
    """List all members (active + pending) from customers/{customer_id}/members/."""
    from backend.shared.firestore import get_db

    db = get_db()
    docs = [
        doc
        async for doc in db.collection("customers")
        .document(customer_id)
        .collection("members")
        .stream()
    ]

    members: list[MemberInfo] = []
    for doc in docs:
        data: dict[str, Any] = doc.to_dict()  # type: ignore[assignment]
        if data.get("status") == "removed":
            continue
        members.append(
            MemberInfo(
                email_hash=doc.id,
                email=data.get("email", ""),
                role=data.get("role", "viewer"),
                status=data.get("status", "pending"),
                invited_by=data.get("invited_by", ""),
                invited_at=data.get("invited_at", ""),
                accepted_at=data.get("accepted_at"),
                last_accessed_at=data.get("last_accessed_at"),
            )
        )

    return members


async def invite_member(
    customer_id: str,
    email: str,
    role: str,
    invited_by: str,
    tier: str,
) -> MemberInfo:
    """Invite a new team member.

    1. Check feature: "team_members" in features
    2. Check member_limit from TIER_CONFIG
    3. Validate role in ("admin", "viewer") — owner is immutable
    4. Check duplicate: SHA-256(email.lower()) as doc ID
    5. Write to customers/{customer_id}/members/{email_hash}
    6. Send Postmark "member-invitation" template
    7. Return MemberInfo
    """
    from fastapi import HTTPException

    from backend.shared.firestore import get_db
    from backend.shared.tier_config import TIER_CONFIG

    if role not in ("admin", "viewer"):
        raise HTTPException(status_code=400, detail="Role must be admin or viewer")

    tier_cfg = TIER_CONFIG.get(tier, {})
    member_limit: int | None = tier_cfg.get("member_limit")

    db = get_db()
    members_ref = db.collection("customers").document(customer_id).collection("members")

    # Count active + pending members
    existing = [doc async for doc in members_ref.stream()]
    active_count = sum(
        1
        for doc in existing
        if doc.to_dict().get("status") in ("active", "pending")  # type: ignore[union-attr]
    )

    if member_limit is not None and active_count >= member_limit:
        raise HTTPException(
            status_code=409,
            detail=f"Member limit reached ({member_limit})",
        )

    # Check duplicate
    email_h = _email_hash(email)
    existing_doc = await members_ref.document(email_h).get()
    if existing_doc.exists:
        existing_data: dict[str, Any] = existing_doc.to_dict()  # type: ignore[assignment]
        if existing_data.get("status") in ("active", "pending"):
            raise HTTPException(
                status_code=409,
                detail="Member already invited",
            )

    now = datetime.now(UTC).isoformat()
    member_data: dict[str, Any] = {
        "email": email.lower(),
        "role": role,
        "invited_by": invited_by,
        "invited_at": now,
        "accepted_at": None,
        "last_accessed_at": None,
        "status": "pending",
    }

    await members_ref.document(email_h).set(member_data)

    # Send invitation email (non-fatal)
    try:
        from backend.billing.email_sender import send_template_email

        await send_template_email(
            to=email.lower(),
            template_alias="member-invitation",
            template_model={
                "role": role,
                "invited_by": invited_by,
                "login_url": "https://dashboard.complyform.dev/auth/login",
            },
        )
    except Exception:
        _log.exception("Failed to send invitation email to %s", email)

    return MemberInfo(
        email_hash=email_h,
        email=email.lower(),
        role=role,
        status="pending",
        invited_by=invited_by,
        invited_at=now,
        accepted_at=None,
        last_accessed_at=None,
    )


async def remove_member(
    customer_id: str,
    email_hash: str,
    actor_email: str,
) -> None:
    """Remove member — set status='removed' and revoke active sessions.

    Cannot remove owner.
    """
    from fastapi import HTTPException

    from backend.shared.firestore import get_db

    db = get_db()
    doc_ref = (
        db.collection("customers")
        .document(customer_id)
        .collection("members")
        .document(email_hash)
    )
    doc = await doc_ref.get()
    if not doc.exists:
        raise HTTPException(status_code=404, detail="Member not found")

    data: dict[str, Any] = doc.to_dict()  # type: ignore[assignment]
    if data.get("role") == "owner":
        raise HTTPException(status_code=409, detail="Cannot remove owner")

    await doc_ref.update({"status": "removed"})

    # Revoke active sessions for this member
    member_email = data.get("email", "")
    if member_email:
        try:
            query = db.collection("sessions").where("email", "==", member_email)
            session_docs = [d async for d in query.stream()]
            for sess_doc in session_docs:
                await db.collection("sessions").document(sess_doc.id).delete()
        except Exception:
            _log.exception("Failed to revoke sessions for %s", member_email)


async def update_member_role(
    customer_id: str,
    email_hash: str,
    new_role: str,
    actor_email: str,
) -> MemberInfo:
    """Change member role. Cannot change owner role. Viewer <-> admin only."""
    from fastapi import HTTPException

    from backend.shared.firestore import get_db

    if new_role not in ("admin", "viewer"):
        raise HTTPException(status_code=400, detail="Role must be admin or viewer")

    db = get_db()
    doc_ref = (
        db.collection("customers")
        .document(customer_id)
        .collection("members")
        .document(email_hash)
    )
    doc = await doc_ref.get()
    if not doc.exists:
        raise HTTPException(status_code=404, detail="Member not found")

    data: dict[str, Any] = doc.to_dict()  # type: ignore[assignment]
    if data.get("role") == "owner":
        raise HTTPException(status_code=409, detail="Cannot change owner role")

    await doc_ref.update({"role": new_role})

    return MemberInfo(
        email_hash=email_hash,
        email=data.get("email", ""),
        role=new_role,
        status=data.get("status", ""),
        invited_by=data.get("invited_by", ""),
        invited_at=data.get("invited_at", ""),
        accepted_at=data.get("accepted_at"),
        last_accessed_at=data.get("last_accessed_at"),
    )


async def accept_invitation(customer_id: str, email: str) -> None:
    """Called during OAuth callback when member authenticates.

    Updates accepted_at and status from 'pending' to 'active'.
    """
    from backend.shared.firestore import get_db

    email_h = _email_hash(email)
    db = get_db()
    doc_ref = (
        db.collection("customers")
        .document(customer_id)
        .collection("members")
        .document(email_h)
    )
    doc = await doc_ref.get()
    if not doc.exists:
        return

    data: dict[str, Any] = doc.to_dict()  # type: ignore[assignment]
    if data.get("status") != "pending":
        return

    now = datetime.now(UTC).isoformat()
    await doc_ref.update({"status": "active", "accepted_at": now})


async def resend_invitation(customer_id: str, email_hash: str) -> None:
    """Resend Postmark member-invitation for pending members."""
    from fastapi import HTTPException

    from backend.shared.firestore import get_db

    db = get_db()
    doc_ref = (
        db.collection("customers")
        .document(customer_id)
        .collection("members")
        .document(email_hash)
    )
    doc = await doc_ref.get()
    if not doc.exists:
        raise HTTPException(status_code=404, detail="Member not found")

    data: dict[str, Any] = doc.to_dict()  # type: ignore[assignment]
    if data.get("status") != "pending":
        raise HTTPException(status_code=400, detail="Member is not pending")

    member_email = data.get("email", "")
    try:
        from backend.billing.email_sender import send_template_email

        await send_template_email(
            to=member_email,
            template_alias="member-invitation",
            template_model={
                "role": data.get("role", "viewer"),
                "invited_by": data.get("invited_by", ""),
                "login_url": "https://dashboard.complyform.dev/auth/login",
            },
        )
    except Exception:
        _log.exception("Failed to resend invitation email to %s", member_email)
