"""Coaching API endpoints — onboarding, chat, plan, compliance."""

import uuid

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from backend.app.core.auth import get_current_rider
from backend.app.core.database import get_session
from backend.app.models.activity import Activity
from backend.app.models.coaching import CoachingChat
from backend.app.models.rider import Rider
from backend.app.models.training import TrainingPlan
from backend.app.services.coaching import (
    process_chat_message,
    generate_plan,
    get_today_workout,
    calculate_compliance,
)

router = APIRouter()


class MessageRequest(BaseModel):
    message: str


class ChatResponse(BaseModel):
    chat_id: str
    chat_type: str
    status: str
    messages: list[dict]


class PlanResponse(BaseModel):
    id: str
    goal: str
    start_date: str
    end_date: str
    phase: str | None
    description: str | None
    status: str
    weeks: list[dict]


# --- Onboarding ---

@router.post("/onboarding/start")
async def start_onboarding(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Start or resume onboarding chat."""
    # Check for existing active onboarding
    query = (
        select(CoachingChat)
        .where(CoachingChat.rider_id == rider.id)
        .where(CoachingChat.chat_type == "onboarding")
        .where(CoachingChat.status == "active")
        .order_by(CoachingChat.created_at.desc())
        .limit(1)
    )
    result = await session.execute(query)
    chat = result.scalar_one_or_none()

    if chat:
        return {
            "chat_id": str(chat.id),
            "status": chat.status,
            "messages": chat.messages_json or [],
            "onboarding_completed": rider.onboarding_completed,
        }

    # Create new onboarding chat
    chat = CoachingChat(
        rider_id=rider.id,
        chat_type="onboarding",
        status="active",
        messages_json=[],
    )
    session.add(chat)
    await session.commit()
    await session.refresh(chat)

    # Send initial greeting by processing an empty-ish message
    response = await process_chat_message(rider, chat.id, "Привет! Я хочу начать тренировки.", session)

    return {
        "chat_id": str(chat.id),
        "status": chat.status,
        "messages": chat.messages_json or [],
        "onboarding_completed": rider.onboarding_completed,
    }


@router.get("/onboarding/status")
async def get_onboarding_status(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Check onboarding status."""
    return {
        "onboarding_completed": rider.onboarding_completed,
        "coaching_profile": rider.coaching_profile,
    }


# --- Chat ---

@router.post("/chat/new")
async def create_chat(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Create a new general coaching chat."""
    chat = CoachingChat(
        rider_id=rider.id,
        chat_type="general",
        status="active",
        messages_json=[],
    )
    session.add(chat)
    await session.commit()
    await session.refresh(chat)
    return {"chat_id": str(chat.id), "status": "active", "messages": []}


@router.get("/chats")
async def list_chats(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """List all coaching chats."""
    query = (
        select(CoachingChat)
        .where(CoachingChat.rider_id == rider.id)
        .order_by(CoachingChat.updated_at.desc())
        .limit(20)
    )
    result = await session.execute(query)
    chats = result.scalars().all()
    return [
        {
            "id": str(c.id),
            "chat_type": c.chat_type,
            "status": c.status,
            "message_count": len(c.messages_json or []),
            "created_at": c.created_at.isoformat() if c.created_at else None,
            "updated_at": c.updated_at.isoformat() if c.updated_at else None,
            "last_message": (c.messages_json[-1]["text"][:100] if c.messages_json else None),
        }
        for c in chats
    ]


@router.get("/chat/{chat_id}")
async def get_chat(
    chat_id: uuid.UUID,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Get chat with messages."""
    chat = await session.get(CoachingChat, chat_id)
    if not chat or chat.rider_id != rider.id:
        raise HTTPException(status_code=404, detail="Chat not found")
    return {
        "chat_id": str(chat.id),
        "chat_type": chat.chat_type,
        "status": chat.status,
        "messages": chat.messages_json or [],
    }


@router.post("/chat/{chat_id}/message")
async def send_message(
    chat_id: uuid.UUID,
    body: MessageRequest,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Send a message to the coaching chat."""
    response = await process_chat_message(rider, chat_id, body.message, session)

    chat = await session.get(CoachingChat, chat_id)
    return {
        "response": response,
        "chat_id": str(chat_id),
        "status": chat.status if chat else "active",
        "messages": chat.messages_json if chat else [],
        "onboarding_completed": rider.onboarding_completed,
    }


# --- Training Plan ---

@router.post("/plan/generate")
async def create_plan(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Generate a new AI training plan."""
    plan = await generate_plan(rider, session)
    return _plan_to_dict(plan)


@router.get("/plan/active")
async def get_active_plan(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Get the active training plan."""
    query = (
        select(TrainingPlan)
        .where(TrainingPlan.rider_id == rider.id)
        .where(TrainingPlan.status == "active")
        .order_by(TrainingPlan.created_at.desc())
        .limit(1)
    )
    result = await session.execute(query)
    plan = result.scalar_one_or_none()
    if not plan:
        return None
    return _plan_to_dict(plan)


@router.get("/plan/{plan_id}/compliance")
async def get_plan_compliance(
    plan_id: uuid.UUID,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Get compliance data for a plan."""
    plan = await session.get(TrainingPlan, plan_id)
    if not plan or plan.rider_id != rider.id:
        raise HTTPException(status_code=404, detail="Plan not found")
    compliance = await calculate_compliance(plan, session)
    return compliance


@router.get("/today")
async def get_today(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Get today's planned workout with linked activity if any."""
    workout = await get_today_workout(rider, session)
    if not workout:
        return None

    # Check if there's already a linked activity for today
    linked_query = (
        select(Activity)
        .where(Activity.training_plan_id == uuid.UUID(workout["plan_id"]))
        .where(Activity.plan_week == workout["week_number"])
        .where(Activity.plan_day == workout["day"])
    )
    linked_result = await session.execute(linked_query)
    linked = linked_result.scalar_one_or_none()
    workout["linked_activity_id"] = str(linked.id) if linked else None
    workout["completed"] = linked is not None
    return workout


# --- Activity-Plan linking ---

class LinkRequest(BaseModel):
    activity_id: str
    plan_id: str
    week: int
    day: str


@router.post("/link")
async def link_activity(
    body: LinkRequest,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Manually link an activity to a planned workout day."""
    activity = await session.get(Activity, uuid.UUID(body.activity_id))
    if not activity or activity.rider_id != rider.id:
        raise HTTPException(status_code=404, detail="Activity not found")

    plan = await session.get(TrainingPlan, uuid.UUID(body.plan_id))
    if not plan or plan.rider_id != rider.id:
        raise HTTPException(status_code=404, detail="Plan not found")

    activity.training_plan_id = plan.id
    activity.plan_week = body.week
    activity.plan_day = body.day
    await session.commit()
    return {"ok": True}


@router.post("/unlink/{activity_id}")
async def unlink_activity(
    activity_id: uuid.UUID,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Remove link between activity and planned workout."""
    activity = await session.get(Activity, activity_id)
    if not activity or activity.rider_id != rider.id:
        raise HTTPException(status_code=404, detail="Activity not found")

    activity.training_plan_id = None
    activity.plan_week = None
    activity.plan_day = None
    await session.commit()
    return {"ok": True}


# --- Adjustment chat ---

@router.post("/plan/adjust")
async def start_plan_adjustment(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Start an adjustment chat for the active plan."""
    # Check active plan exists
    plan_query = (
        select(TrainingPlan)
        .where(TrainingPlan.rider_id == rider.id)
        .where(TrainingPlan.status == "active")
        .limit(1)
    )
    plan_result = await session.execute(plan_query)
    plan = plan_result.scalar_one_or_none()
    if not plan:
        raise HTTPException(status_code=400, detail="No active plan to adjust")

    chat = CoachingChat(
        rider_id=rider.id,
        chat_type="adjustment",
        status="active",
        messages_json=[],
    )
    session.add(chat)
    await session.commit()
    await session.refresh(chat)

    # Start with context about what needs adjustment
    response = await process_chat_message(
        rider, chat.id,
        "Мне нужно скорректировать мой текущий план тренировок. Посмотри на мои последние данные и предложи изменения.",
        session,
    )

    return {
        "chat_id": str(chat.id),
        "status": chat.status,
        "messages": chat.messages_json or [],
        "response": response,
    }


def _plan_to_dict(plan: TrainingPlan) -> dict:
    weeks = plan.weeks_json.get("weeks", []) if plan.weeks_json else []
    return {
        "id": str(plan.id),
        "goal": plan.goal,
        "start_date": plan.start_date.isoformat(),
        "end_date": plan.end_date.isoformat(),
        "phase": plan.phase,
        "description": plan.description,
        "status": plan.status,
        "weeks": weeks,
    }
