"""
改善行动计划模块测试
"""
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from datetime import datetime, timedelta
from tests.conftest import create_test_user, get_token_for_user, auth_header, create_test_kpi
from app.models import ActionPlan, Objective, KR


def create_test_objective_kr(db: Session, **kwargs):
    """创建测试目标+KR（行动挂KR 2026-08-27）"""
    obj = Objective(
        entity_id=kwargs.get("entity_id", 1),
        title=kwargs.get("objective_title", "测试目标"),
        quarter="2026Q3",
        status="active",
    )
    db.add(obj)
    db.commit()
    db.refresh(obj)
    kr = KR(
        entity_id=kwargs.get("entity_id", 1),
        objective_id=obj.id,
        title=kwargs.get("kr_title", "测试KR"),
        operator=">=",
        weight=50,
        target_value=100,
    )
    db.add(kr)
    db.commit()
    db.refresh(kr)
    return obj, kr


def create_test_plan(db: Session, **kwargs) -> ActionPlan:
    """创建测试行动计划"""
    defaults = {
        "kpi_id": 1,
        "title": "测试改善计划",
        "assignee": "张三",
        "priority": "medium",
        "status": "pending",
        "progress": 0,
        "created_by": "testadmin",
    }
    defaults.update(kwargs)
    plan = ActionPlan(**defaults)
    db.add(plan)
    db.commit()
    db.refresh(plan)
    return plan


class TestActionPlans:
    """改善行动计划CRUD测试"""

    def test_list_empty(self, client: TestClient, db: Session):
        """空列表"""
        create_test_user(db)
        token = get_token_for_user(client)

        resp = client.get("/api/cma/action-plans", headers=auth_header(token))
        assert resp.status_code == 200
        data = resp.json()
        assert data["data"] == []

    def test_create_plan(self, client: TestClient, db: Session):
        """创建行动计划"""
        create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)

        resp = client.post(
            "/api/cma/action-plans",
            headers=auth_header(token),
            json={
                "title": "提升营收10%",
                "kpi_id": kpi.id,
                "assignee": "张三",
                "priority": "high",
                "description": "通过增加销售渠道提升营收",
                "due_date": (datetime.now() + timedelta(days=30)).isoformat(),
            },
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["title"] == "提升营收10%"
        assert data["kpi_id"] == kpi.id
        assert data["priority"] == "high"
        assert data["status"] == "pending"
        assert data["progress"] == 0

    def test_create_plan_missing_required(self, client: TestClient, db: Session):
        """缺少必填字段"""
        create_test_user(db)
        token = get_token_for_user(client)

        resp = client.post(
            "/api/cma/action-plans",
            headers=auth_header(token),
            json={"title": "不完整计划"},
        )
        assert resp.status_code == 400
        assert "缺少" in resp.json()["detail"]

    def test_list_with_data(self, client: TestClient, db: Session):
        """有数据时列表正常"""
        user = create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        create_test_plan(db, kpi_id=kpi.id, title="计划A")
        create_test_plan(db, kpi_id=kpi.id, title="计划B")

        resp = client.get("/api/cma/action-plans", headers=auth_header(token))
        assert resp.status_code == 200
        data = resp.json()
        assert len(data["data"]) == 2

    def test_filter_by_status(self, client: TestClient, db: Session):
        """按状态过滤"""
        user = create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        create_test_plan(db, kpi_id=kpi.id, title="待开始", status="pending")
        create_test_plan(db, kpi_id=kpi.id, title="进行中", status="in_progress")
        create_test_plan(db, kpi_id=kpi.id, title="已完成", status="completed")

        resp = client.get("/api/cma/action-plans?status=in_progress", headers=auth_header(token))
        assert resp.status_code == 200
        data = resp.json()
        assert len(data["data"]) == 1
        assert data["data"][0]["title"] == "进行中"

    def test_filter_by_keyword(self, client: TestClient, db: Session):
        """关键词搜索：keyword 应过滤 title（期望行为，2026-08-27 TDD示范）"""
        user = create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        create_test_plan(db, kpi_id=kpi.id, title="提升营收计划")
        create_test_plan(db, kpi_id=kpi.id, title="降低成本计划")

        resp = client.get("/api/cma/action-plans?keyword=营收", headers=auth_header(token))
        assert resp.status_code == 200
        data = resp.json()
        # 期望行为：keyword 过滤生效，只返回标题含"营收"的1条
        assert len(data["data"]) == 1
        assert data["data"][0]["title"] == "提升营收计划"

    def test_update_plan(self, client: TestClient, db: Session):
        """更新行动计划"""
        user = create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        plan = create_test_plan(db, kpi_id=kpi.id)

        resp = client.put(
            f"/api/cma/action-plans/{plan.id}",
            headers=auth_header(token),
            json={
                "title": "已修改的计划",
                "status": "in_progress",
                "progress": 50,
                "priority": "high",
            },
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["title"] == "已修改的计划"
        assert data["status"] == "in_progress"
        assert data["progress"] == 50
        assert data["priority"] == "high"

    def test_update_plan_not_found(self, client: TestClient, db: Session):
        """更新不存在的计划"""
        create_test_user(db)
        token = get_token_for_user(client)

        resp = client.put(
            "/api/cma/action-plans/9999",
            headers=auth_header(token),
            json={"title": "不存在"},
        )
        assert resp.status_code == 404

    def test_update_plan_progress_clamp(self, client: TestClient, db: Session):
        """进度值被限制在0-100"""
        user = create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        plan = create_test_plan(db, kpi_id=kpi.id)

        resp = client.put(
            f"/api/cma/action-plans/{plan.id}",
            headers=auth_header(token),
            json={"progress": 150},
        )
        assert resp.status_code == 200
        assert resp.json()["progress"] == 100

        resp = client.put(
            f"/api/cma/action-plans/{plan.id}",
            headers=auth_header(token),
            json={"progress": -10},
        )
        assert resp.status_code == 200
        assert resp.json()["progress"] == 0

    def test_delete_plan(self, client: TestClient, db: Session):
        """删除行动计划"""
        user = create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        plan = create_test_plan(db, kpi_id=kpi.id)

        resp = client.delete(
            f"/api/cma/action-plans/{plan.id}",
            headers=auth_header(token),
        )
        assert resp.status_code == 200
        assert resp.json()["message"] == "已删除"

        # 验证已删除
        get_resp = client.get("/api/cma/action-plans", headers=auth_header(token))
        assert len(get_resp.json()["data"]) == 0

    def test_delete_plan_not_found(self, client: TestClient, db: Session):
        """删除不存在的计划"""
        create_test_user(db)
        token = get_token_for_user(client)

        resp = client.delete(
            "/api/cma/action-plans/9999",
            headers=auth_header(token),
        )
        assert resp.status_code == 404

    def test_stats(self, client: TestClient, db: Session):
        """统计接口"""
        user = create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        create_test_plan(db, kpi_id=kpi.id, title="待开始", status="pending")
        create_test_plan(db, kpi_id=kpi.id, title="进行中", status="in_progress")
        create_test_plan(db, kpi_id=kpi.id, title="已完成", status="completed")

        resp = client.get("/api/cma/action-plans/stats", headers=auth_header(token))
        assert resp.status_code == 200
        data = resp.json()
        assert data["total"] == 3
        assert data["pending"] == 1
        assert data["in_progress"] == 1
        assert data["completed"] == 1

    # ── 行动挂KR (2026-08-27) ──

    def test_create_plan_with_kr_id(self, client: TestClient, db: Session):
        """创建行动时挂KR：返回kr_id，objective_id从KR自动继承"""
        create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        obj, kr = create_test_objective_kr(db)

        resp = client.post(
            "/api/cma/action-plans",
            headers=auth_header(token),
            json={
                "title": "降低费用率行动",
                "kpi_id": kpi.id,
                "kr_id": kr.id,
                "assignee": "张三",
            },
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["kr_id"] == kr.id
        # 未显式传objective_id时从KR继承
        assert data["objective_id"] == obj.id

    def test_create_plan_kr_not_found(self, client: TestClient, db: Session):
        """kr_id不存在 → 404"""
        create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)

        resp = client.post(
            "/api/cma/action-plans",
            headers=auth_header(token),
            json={"title": "行动", "kpi_id": kpi.id, "kr_id": 99999},
        )
        assert resp.status_code == 404

    def test_list_includes_kr_title(self, client: TestClient, db: Session):
        """列表返回kr_title"""
        create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        obj, kr = create_test_objective_kr(db)
        create_test_plan(db, kpi_id=kpi.id, kr_id=kr.id, title="挂KR的行动")

        resp = client.get("/api/cma/action-plans", headers=auth_header(token))
        assert resp.status_code == 200
        data = resp.json()["data"]
        item = data[0]
        assert item["kr_id"] == kr.id
        assert item["kr_title"] == "测试KR"

    def test_update_plan_kr_id(self, client: TestClient, db: Session):
        """更新行动可改挂KR"""
        create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        obj1, kr1 = create_test_objective_kr(db, kr_title="KR一")
        obj2, kr2 = create_test_objective_kr(db, kr_title="KR二")
        plan = create_test_plan(db, kpi_id=kpi.id, kr_id=kr1.id, title="行动")

        resp = client.put(
            f"/api/cma/action-plans/{plan.id}",
            headers=auth_header(token),
            json={"kr_id": kr2.id},
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["kr_id"] == kr2.id

    def test_update_plan_kr_clear(self, client: TestClient, db: Session):
        """更新行动可置空kr_id"""
        create_test_user(db)
        token = get_token_for_user(client)
        kpi = create_test_kpi(db)
        obj, kr = create_test_objective_kr(db)
        plan = create_test_plan(db, kpi_id=kpi.id, kr_id=kr.id, title="行动")

        resp = client.put(
            f"/api/cma/action-plans/{plan.id}",
            headers=auth_header(token),
            json={"kr_id": None},
        )
        assert resp.status_code == 200
        assert resp.json()["kr_id"] is None
