# app/services/assignment.py

from typing import Optional
from sqlalchemy.orm import selectinload
from sqlalchemy.sql import func
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.agent import  Agent, AgentAssignmentHistory
from app.models.visitor import Visitor
from app.models.client import Client
from app.schemas.agent import VisitorSummary
from datetime import datetime ,timezone
from zoneinfo import ZoneInfo

async def get_current_assignment( db: AsyncSession, visitor_id: int ) -> Optional[AgentAssignmentHistory]:
    result = await db.execute(
        select(AgentAssignmentHistory)
        .where(AgentAssignmentHistory.visitor_id == visitor_id, AgentAssignmentHistory.ended_at.is_(None))
    )
    return result.scalar_one_or_none()


async def assign_agent_to_visitor( db: AsyncSession, agent_id: int, visitor_id: int ) -> AgentAssignmentHistory:
    # Check if already assigned
    existing = await get_current_assignment(db, visitor_id)
    if existing:
        # If it's already this agent, just return
        if existing.agent_id == agent_id:
            return existing
        # Otherwise raise
        raise ValueError("Visitor already assigned to another agent")

    assignment = AgentAssignmentHistory(
        agent_id=agent_id,
        visitor_id=visitor_id,
    )
    db.add(assignment)
    await db.commit()
    await db.refresh(assignment)
    return assignment


async def release_assignment(db: AsyncSession, agent_id: int, visitor_id: int) -> None:
    
    current = await get_current_assignment(db, visitor_id)
    
    if not current:
        return

    if current.agent_id != agent_id:
        raise ValueError("You are not assigned to this visitor")

    current.ended_at = datetime.now(timezone.utc)  

    await db.commit()


async def is_agent_allowed_to_send( db: AsyncSession, agent_id: int, visitor_id: int ) -> bool:
    """
    Rule: if visitor has an active assignment → ONLY that agent can send.
          if no assignment → agent must first assign.
    """
    assignment = await get_current_assignment(db, visitor_id)
    if not assignment:
        return False
    return assignment.agent_id == agent_id


async def get_dashboard_visitors( db: AsyncSession ) -> list[VisitorSummary]:
    """
    Returns all visitors + last message + current assignment.
    """
    
    # Load visitors + related client + messages
    result = await db.execute(
        select(Visitor)
        .options(
            selectinload(Visitor.client),
            selectinload(Visitor.messages),
        )
        .order_by(Visitor.created_at.desc())
    )
    visitors = result.scalars().all()

    summaries: list[VisitorSummary] = []

    for v in visitors:
        # last message
        last_msg = None
        if v.messages:
            last_msg = max(v.messages, key=lambda m: m.created_at or func.now())

        # current assignment
        current_assignment = await get_current_assignment(db, v.id)
        assigned_agent_id = None
        assigned_agent_name = None
        if current_assignment:
            agent_result = await db.execute(
                select(Agent).where(Agent.id == current_assignment.agent_id)
            )
            ag = agent_result.scalar_one_or_none()
            if ag:
                assigned_agent_id = ag.id
                assigned_agent_name = ag.name

        summaries.append(
            VisitorSummary(
                visitor_id=v.id,
                visitor_uid=v.visitor_id,
                client_id=v.client_id,
                client_name=getattr(v.client, "client_name", None),
                website_url=getattr(v.client, "website_url", None),
                last_message_text=getattr(last_msg, "text", None),
                last_message_at=getattr(last_msg, "created_at", None),
                assigned_agent_id=assigned_agent_id,
                assigned_agent_name=assigned_agent_name,
            )
        )

    return summaries
