"""Decision logic for intelligent eval workers (决策逻辑).

Worker analyzes current situation and decides what to do:
- execute_session: Execute a new session
- wait: Wait for next tick
- start_analysis: Start analysis (all sessions completed)
"""

from datetime import datetime, timedelta
from enum import Enum
from typing import Optional

from sqlmodel import Session, select

from agenteval.intelligent_eval.models import IntelligentEvalStatus
from agenteval.storage.db import (
    IntelligentEvalDB,
    IntelligentEvalSessionDB,
    as_utc,
    utc_now,
)


class DecisionType(str, Enum):
    """Decision types for worker."""

    EXECUTE_SESSION = "execute_session"
    WAIT = "wait"
    START_ANALYSIS = "start_analysis"


class Decision:
    """A decision made by a worker."""

    def __init__(self, decision_type: DecisionType, reason: str, context: dict):
        self.decision_type = decision_type
        self.reason = reason
        self.context = context

    def to_dict(self) -> dict:
        return {
            "decision_type": self.decision_type.value,
            "reason": self.reason,
            "context": self.context,
        }


def _parse_time_slot(time_slot: str) -> Optional[tuple[int, int]]:
    """Parse time slot string (e.g., "8-10h") to (start_hour, end_hour).

    Returns:
        (start_hour, end_hour) tuple, or None if invalid format
    """
    try:
        parts = time_slot.replace("h", "").split("-")
        if len(parts) != 2:
            return None
        return (int(parts[0]), int(parts[1]))
    except (ValueError, AttributeError):
        return None


def _get_current_slot(time_distribution: list[dict], current_offset: timedelta) -> Optional[dict]:
    """Get current time slot based on offset.

    Returns:
        Current slot dict, or None if not in any slot
    """
    current_hours = current_offset.total_seconds() / 3600

    for slot in time_distribution:
        time_slot = slot.get("time_slot", "")
        parsed = _parse_time_slot(time_slot)
        if parsed is None:
            continue

        start_hour, end_hour = parsed
        if start_hour <= current_hours < end_hour:
            return slot

    return None


def _count_sessions_in_slot(
    eval_id: str, slot: dict, eval_started_at: datetime, session: Session
) -> int:
    """Count sessions created in a time slot.

    Args:
        eval_id: Evaluation ID
        slot: Time slot dict (e.g., {"time_slot": "8-10h", "sessions": 2})
        eval_started_at: When the eval started
        session: Database session

    Returns:
        Number of sessions created in this slot
    """
    time_slot = slot.get("time_slot", "")
    parsed = _parse_time_slot(time_slot)
    if parsed is None:
        return 0

    start_hour, end_hour = parsed
    
    # Convert to naive datetime for SQLite comparison
    slot_start = (as_utc(eval_started_at) + timedelta(hours=start_hour)).replace(tzinfo=None)
    slot_end = (as_utc(eval_started_at) + timedelta(hours=end_hour)).replace(tzinfo=None)

    # Count sessions created within slot time range
    sessions = session.exec(
        select(IntelligentEvalSessionDB).where(
            IntelligentEvalSessionDB.eval_id == eval_id,
            IntelligentEvalSessionDB.created_at >= slot_start,
            IntelligentEvalSessionDB.created_at < slot_end,
        )
    ).all()

    return len(sessions)


def _has_high_severity_issues(eval_id: str, session: Session) -> bool:
    """Check if any completed session has high severity issues.

    Returns:
        True if any session's verdict contains high severity issue
    """
    completed_sessions = session.exec(
        select(IntelligentEvalSessionDB).where(
            IntelligentEvalSessionDB.eval_id == eval_id,
            IntelligentEvalSessionDB.status == "completed",
        )
    ).all()

    for sess in completed_sessions:
        verdict = sess.get_verdict()
        if verdict and verdict.get("severity") == "high":
            return True

    return False


def make_decision(eval_db: IntelligentEvalDB, session: Session) -> Decision:
    """Make a decision based on current evaluation state.

    Args:
        eval_db: Evaluation database record
        session: Database session

    Returns:
        Decision object
    """
    # Check if eval is still executing
    if eval_db.status != IntelligentEvalStatus.EXECUTING.value:
        return Decision(
            DecisionType.WAIT,
            f"评估状态为 {eval_db.status}，不在执行中",
            {"status": eval_db.status},
        )

    # Check if eval has plan and started_at
    if not eval_db.plan or not eval_db.started_at:
        return Decision(
            DecisionType.WAIT,
            "评估缺少计划或未开始",
            {"has_plan": bool(eval_db.plan), "has_started_at": bool(eval_db.started_at)},
        )

    plan = eval_db.get_plan()
    time_distribution = plan.get("time_distribution", [])
    estimated_sessions = plan.get("estimated_sessions", 0)

    # Calculate current offset
    current_offset = utc_now() - as_utc(eval_db.started_at)
    current_hours = current_offset.total_seconds() / 3600

    # Get all sessions
    all_sessions = session.exec(
        select(IntelligentEvalSessionDB).where(IntelligentEvalSessionDB.eval_id == eval_db.id)
    ).all()

    completed_sessions = [s for s in all_sessions if s.status == "completed"]

    # Check if all sessions completed and estimated reached
    if len(completed_sessions) >= estimated_sessions:
        return Decision(
            DecisionType.START_ANALYSIS,
            f"所有 {estimated_sessions} 个会话已完成，开始分析",
            {
                "completed_sessions": len(completed_sessions),
                "estimated_sessions": estimated_sessions,
            },
        )

    # Get current time slot
    current_slot = _get_current_slot(time_distribution, current_offset)

    if current_slot is None:
        return Decision(
            DecisionType.WAIT,
            f"当前时间偏移 {current_hours:.1f}h 不在任何时段内",
            {"current_offset_hours": current_hours},
        )

    # Check if current slot has deficit
    slot_name = current_slot.get("time_slot", "")
    expected_sessions = current_slot.get("sessions", 0)
    current_sessions = _count_sessions_in_slot(eval_db.id, current_slot, eval_db.started_at, session)

    deficit = expected_sessions - current_sessions

    if deficit > 0:
        return Decision(
            DecisionType.EXECUTE_SESSION,
            f"时段 {slot_name} 欠账 {deficit} 个会话",
            {
                "current_slot": slot_name,
                "expected_sessions": expected_sessions,
                "current_sessions": current_sessions,
                "deficit": deficit,
            },
        )

    # Check if any high severity issues found
    if _has_high_severity_issues(eval_db.id, session):
        return Decision(
            DecisionType.EXECUTE_SESSION,
            "发现高严重度问题，需要深入挖掘",
            {"has_high_severity": True},
        )

    # No deficit, no high severity issues, wait
    return Decision(
        DecisionType.WAIT,
        f"时段 {slot_name} 无欠账，等待下一时段",
        {
            "current_slot": slot_name,
            "expected_sessions": expected_sessions,
            "current_sessions": current_sessions,
        },
    )


def is_eval_completed(eval_db: IntelligentEvalDB, session: Session) -> bool:
    """Check if evaluation is completed.

    An eval is completed when:
    1. All sessions are completed
    2. Report is submitted

    Returns:
        True if eval is completed
    """
    if eval_db.status != IntelligentEvalStatus.EXECUTING.value:
        return False

    if not eval_db.plan:
        return False

    plan = eval_db.get_plan()
    estimated_sessions = plan.get("estimated_sessions", 0)

    # Check if all sessions completed
    all_sessions = session.exec(
        select(IntelligentEvalSessionDB).where(IntelligentEvalSessionDB.eval_id == eval_db.id)
    ).all()

    completed_sessions = [s for s in all_sessions if s.status == "completed"]

    if len(completed_sessions) < estimated_sessions:
        return False

    # Check if report submitted
    if not eval_db.report:
        return False

    return True
