import sys
from datetime import datetime
from unittest.mock import Mock

import pytest
from sqlalchemy import select
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine

sys.modules.setdefault("psutil", Mock())

import app.models  # noqa: F401
from app.models.goal import Goal
from app.models.reminder import Reminder
from app.models.task import Task, TaskPriority, TaskStatus
from app.models.todo import DailyTodo
from app.models.user import User
from app.services.auth_service import get_password_hash


@pytest.fixture
async def tool_env(tmp_path):
    db_path = tmp_path / "test_task_tools.db"
    engine = create_async_engine(f"sqlite+aiosqlite:///{db_path}", future=True)
    session_factory = async_sessionmaker(engine, expire_on_commit=False)

    async with engine.begin() as conn:
        # 只创建本测试需要的表，避免全量 metadata 引入未注册的外键表。
        await conn.run_sync(User.metadata.create_all, tables=[
            User.__table__,
            Task.__table__,
            DailyTodo.__table__,
            Reminder.__table__,
            Goal.__table__,
        ])

    async with session_factory() as session:
        user = User(
            username="tool_user",
            email="tool@example.com",
            hashed_password=get_password_hash("secret123"),
            full_name="Tool Tester",
        )
        session.add(user)
        await session.commit()
        await session.refresh(user)

    try:
        yield {"session_factory": session_factory, "user_id": user.id}
    finally:
        await engine.dispose()


@pytest.mark.asyncio
async def test_create_task_accepts_content_and_date_aliases_and_persists_task(tool_env, monkeypatch):
    from app.agents.tools import task as task_tools

    monkeypatch.setattr(task_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(task_tools, "get_current_user", lambda: tool_env["user_id"])

    result = task_tools.create_task.func(content="完成对话系统", date="2026-03-28")

    assert "任务创建成功" in result

    async with tool_env["session_factory"]() as session:
        saved = (await session.execute(select(Task))).scalar_one()

    assert saved.title == "完成对话系统"
    assert saved.description == "完成对话系统"
    assert saved.priority == TaskPriority.MEDIUM
    assert saved.status == TaskStatus.TODO
    assert saved.due_date == datetime(2026, 3, 28, 0, 0)


@pytest.mark.asyncio
async def test_create_schedule_task_accepts_content_and_date_aliases_and_sets_morning_due_date(tool_env, monkeypatch):
    from app.agents.tools import schedule as schedule_tools

    monkeypatch.setattr(schedule_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(schedule_tools, "get_current_user", lambda: tool_env["user_id"])

    result = schedule_tools.create_schedule_task.func(content="完成对话系统", date="2026-03-28")

    assert "任务创建成功" in result

    async with tool_env["session_factory"]() as session:
        saved = (await session.execute(select(Task))).scalar_one()

    assert saved.title == "完成对话系统"
    assert saved.description == "完成对话系统"
    assert saved.priority == TaskPriority.MEDIUM
    assert saved.status == TaskStatus.TODO
    assert saved.due_date == datetime(2026, 3, 28, 9, 0)


@pytest.mark.asyncio
@pytest.mark.parametrize(
    ("priority_input", "expected"),
    [
        (1, TaskPriority.LOW),
        (2, TaskPriority.MEDIUM),
        (3, TaskPriority.HIGH),
        (4, TaskPriority.URGENT),
        ("urgent", TaskPriority.URGENT),
    ],
)
async def test_create_task_normalizes_legacy_and_string_priorities(tool_env, monkeypatch, priority_input, expected):
    from app.agents.tools import task as task_tools

    monkeypatch.setattr(task_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(task_tools, "get_current_user", lambda: tool_env["user_id"])

    result = task_tools.create_task.func(title=f"priority-{priority_input}", priority=priority_input)

    assert "任务创建成功" in result

    async with tool_env["session_factory"]() as session:
        rows = (await session.execute(select(Task).order_by(Task.created_at.asc()))).scalars().all()

    assert rows[-1].priority == expected


@pytest.mark.asyncio
async def test_create_task_accepts_iso_datetime_due_date(tool_env, monkeypatch):
    from app.agents.tools import task as task_tools

    monkeypatch.setattr(task_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(task_tools, "get_current_user", lambda: tool_env["user_id"])

    result = task_tools.create_task.func(title="timed task", due_date="2026-03-28T15:30:00Z")

    assert "任务创建成功" in result

    async with tool_env["session_factory"]() as session:
        saved = (await session.execute(select(Task))).scalar_one()

    assert saved.due_date == datetime(2026, 3, 28, 15, 30, 0)


@pytest.mark.asyncio
async def test_create_task_returns_failure_for_missing_title_and_content(tool_env, monkeypatch):
    from app.agents.tools import task as task_tools

    monkeypatch.setattr(task_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(task_tools, "get_current_user", lambda: tool_env["user_id"])

    result = task_tools.create_task.func()

    assert result == "创建任务失败: title 不能为空"


@pytest.mark.asyncio
async def test_create_task_returns_failure_for_invalid_priority(tool_env, monkeypatch):
    from app.agents.tools import task as task_tools

    monkeypatch.setattr(task_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(task_tools, "get_current_user", lambda: tool_env["user_id"])

    result = task_tools.create_task.func(title="bad priority", priority="top")

    assert "创建任务失败:" in result


@pytest.mark.asyncio
async def test_update_task_status_rejects_invalid_status(tool_env, monkeypatch):
    from app.agents.tools import task as task_tools

    monkeypatch.setattr(task_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(task_tools, "get_current_user", lambda: tool_env["user_id"])

    create_result = task_tools.create_task.func(title="status test")
    assert "任务创建成功" in create_result

    async with tool_env["session_factory"]() as session:
        saved = (await session.execute(select(Task))).scalar_one()



@pytest.mark.asyncio
async def test_get_tasks_filters_by_normalized_status_and_formats_values(tool_env, monkeypatch):
    from app.agents.tools import task as task_tools

    monkeypatch.setattr(task_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(task_tools, "get_current_user", lambda: tool_env["user_id"])

    task_tools.create_task.func(title="todo task", priority="high")
    task_tools.create_task.func(title="done task", priority="low")

    async with tool_env["session_factory"]() as session:
        rows = (await session.execute(select(Task).order_by(Task.created_at.asc()))).scalars().all()
        rows[1].status = TaskStatus.DONE
        await session.commit()

    result = task_tools.get_tasks.func(status="done")

    assert "done task" in result
    assert "todo task" not in result
    assert "状态:done" in result
    assert "优先级:low" in result


@pytest.mark.asyncio
async def test_create_schedule_reminder_accepts_datetime_description_and_at_aliases(tool_env, monkeypatch):
    from app.agents.tools import schedule as schedule_tools

    monkeypatch.setattr(schedule_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(schedule_tools, "get_current_user", lambda: tool_env["user_id"])

    result = schedule_tools.create_reminder.func(
        title="收被子",
        description="提醒收被子",
        datetime="2026-03-29T09:00:00",
        time_zone="Asia/Shanghai",
    )

    assert "提醒创建成功" in result

    async with tool_env["session_factory"]() as session:
        saved = (await session.execute(select(Reminder))).scalar_one()

    assert saved.title == "收被子"
    assert saved.note == "提醒收被子"
    assert saved.reminder_at == datetime(2026, 3, 29, 9, 0)

    result = schedule_tools.create_reminder.func(
        content="收被子",
        datetime="2026-03-29T09:00:00+08:00",
    )

    assert "提醒创建成功" in result

    async with tool_env["session_factory"]() as session:
        rows = (await session.execute(select(Reminder).order_by(Reminder.created_at.asc()))).scalars().all()

    assert rows[-1].title == "收被子"
    assert rows[-1].note is None
    assert rows[-1].reminder_at == datetime(2026, 3, 29, 9, 0)

    result = schedule_tools.create_reminder.func(
        content="收被子",
        time="2026-03-29T09:00:00",
        time_zone="Asia/Shanghai",
    )

    assert "提醒创建成功" in result

    async with tool_env["session_factory"]() as session:
        rows = (await session.execute(select(Reminder).order_by(Reminder.created_at.asc()))).scalars().all()

    assert rows[-1].title == "收被子"
    assert rows[-1].note is None
    assert rows[-1].reminder_at == datetime(2026, 3, 29, 9, 0)

    result = schedule_tools.create_reminder.func(
        title="收被子",
        remind_at="2026-03-29T18:00:00",
    )

    assert "提醒创建成功" in result

    async with tool_env["session_factory"]() as session:
        rows = (await session.execute(select(Reminder).order_by(Reminder.created_at.asc()))).scalars().all()

    assert rows[-1].title == "收被子"
    assert rows[-1].note is None
    assert rows[-1].reminder_at == datetime(2026, 3, 29, 18, 0)


@pytest.mark.asyncio
async def test_create_schedule_reminder_returns_failure_when_time_aliases_missing(tool_env, monkeypatch):
    from app.agents.tools import schedule as schedule_tools

    monkeypatch.setattr(schedule_tools, "async_session", tool_env["session_factory"])
    monkeypatch.setattr(schedule_tools, "get_current_user", lambda: tool_env["user_id"])

    result = schedule_tools.create_reminder.func(title="收被子")

    assert result == "创建提醒失败: reminder_at 不能为空"
