"""
core/routines.py - Shared business logic for routines

This module contains reusable functions for routine operations
that can be called from API routes, bot commands, or scheduler.
"""

import uuid
from datetime import datetime, date
import core.postgres as postgres
import core.tz as tz


def start_session(routine_id, user_uuid):
    """
    Create and start a new routine session.
    Returns the session object or None if routine not found.
    """
    routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
    if not routine:
        return None

    active_session = postgres.select_one(
        "routine_sessions",
        {"user_uuid": user_uuid, "status": "active"}
    )
    if active_session:
        return {"error": "already_active", "session_id": active_session["id"]}

    steps = postgres.select(
        "routine_steps",
        {"routine_id": routine_id},
        order_by="position"
    )
    if not steps:
        return {"error": "no_steps"}

    session = {
        "id": str(uuid.uuid4()),
        "routine_id": routine_id,
        "user_uuid": user_uuid,
        "status": "active",
        "current_step_index": 0,
    }
    result = postgres.insert("routine_sessions", session)
    return {"session": result, "current_step": steps[0]}


def pause_session(session_id, user_uuid):
    """Pause an active session."""
    session = postgres.select_one(
        "routine_sessions",
        {"id": session_id, "user_uuid": user_uuid}
    )
    if not session:
        return None
    if session.get("status") != "active":
        return {"error": "not_active"}
    result = postgres.update(
        "routine_sessions",
        {"status": "paused", "paused_at": tz.user_now().isoformat()},
        {"id": session_id}
    )
    return result


def resume_session(session_id, user_uuid):
    """Resume a paused session."""
    session = postgres.select_one(
        "routine_sessions",
        {"id": session_id, "user_uuid": user_uuid}
    )
    if not session:
        return None
    if session.get("status") != "paused":
        return {"error": "not_paused"}
    result = postgres.update(
        "routine_sessions",
        {"status": "active", "paused_at": None},
        {"id": session_id}
    )
    return result


def abort_session(session_id, user_uuid, reason=None):
    """Abort a session with optional reason."""
    session = postgres.select_one(
        "routine_sessions",
        {"id": session_id, "user_uuid": user_uuid}
    )
    if not session:
        return None
    result = postgres.update(
        "routine_sessions",
        {
            "status": "aborted",
            "abort_reason": reason or "Aborted by user",
            "completed_at": tz.user_now().isoformat()
        },
        {"id": session_id}
    )
    return result


def complete_session(session_id, user_uuid):
    """Mark a session as completed and update streak."""
    session = postgres.select_one(
        "routine_sessions",
        {"id": session_id, "user_uuid": user_uuid}
    )
    if not session:
        return None

    completed_at = tz.user_now()
    result = postgres.update(
        "routine_sessions",
        {"status": "completed", "completed_at": completed_at.isoformat()},
        {"id": session_id}
    )

    _update_streak(user_uuid, session["routine_id"])

    return result


def clone_template(template_id, user_uuid):
    """Clone a template to user's routines."""
    template = postgres.select_one("routine_templates", {"id": template_id})
    if not template:
        return None

    template_steps = postgres.select(
        "routine_template_steps",
        {"template_id": template_id},
        order_by="position"
    )

    new_routine = {
        "id": str(uuid.uuid4()),
        "user_uuid": user_uuid,
        "name": template["name"],
        "description": template.get("description"),
        "icon": template.get("icon"),
    }
    routine = postgres.insert("routines", new_routine)

    for step in template_steps:
        new_step = {
            "id": str(uuid.uuid4()),
            "routine_id": routine["id"],
            "name": step["name"],
            "instructions": step.get("instructions"),
            "step_type": step.get("step_type", "generic"),
            "duration_minutes": step.get("duration_minutes"),
            "media_url": step.get("media_url"),
            "position": step["position"],
        }
        postgres.insert("routine_steps", new_step)

    return routine


STREAK_MILESTONES = {3, 7, 14, 21, 30, 60, 90, 100, 365}


def _update_streak(user_uuid, routine_id):
    """Update streak after completing a session. Resets if day was missed.
    Returns the updated streak dict with optional 'milestone' key."""
    today = tz.user_today()

    streak = postgres.select_one(
        "routine_streaks",
        {"user_uuid": user_uuid, "routine_id": routine_id}
    )

    if not streak:
        new_streak_val = 1
        new_streak = {
            "id": str(uuid.uuid4()),
            "user_uuid": user_uuid,
            "routine_id": routine_id,
            "current_streak": 1,
            "longest_streak": 1,
            "last_completed_date": today.isoformat(),
        }
        result = postgres.insert("routine_streaks", new_streak)
        if new_streak_val in STREAK_MILESTONES:
            result["milestone"] = new_streak_val
        return result

    last_completed = streak.get("last_completed_date")
    if last_completed:
        if isinstance(last_completed, str):
            last_completed = date.fromisoformat(last_completed)
        days_diff = (today - last_completed).days
        if days_diff == 0:
            return streak
        elif days_diff == 1:
            new_streak_val = streak["current_streak"] + 1
        else:
            new_streak_val = 1
    else:
        new_streak_val = 1

    longest = max(streak["longest_streak"], new_streak_val)

    postgres.update(
        "routine_streaks",
        {
            "current_streak": new_streak_val,
            "longest_streak": longest,
            "last_completed_date": today.isoformat(),
        },
        {"id": streak["id"]}
    )

    result = {**streak, "current_streak": new_streak_val, "longest_streak": longest}
    if new_streak_val in STREAK_MILESTONES:
        result["milestone"] = new_streak_val
    return result


def calculate_streak(user_uuid, routine_id):
    """Get current streak for a routine."""
    streak = postgres.select_one(
        "routine_streaks",
        {"user_uuid": user_uuid, "routine_id": routine_id}
    )
    return streak


def get_active_session(user_uuid):
    """Get user's currently active or paused session."""
    session = postgres.select_one(
        "routine_sessions",
        {"user_uuid": user_uuid, "status": "active"}
    )
    if not session:
        session = postgres.select_one(
            "routine_sessions",
            {"user_uuid": user_uuid, "status": "paused"}
        )
    return session
