from datetime import datetime
import uuid

import pytest


def test_projects_list_smoke(client, admin_tokens, auth_headers):
    response = client.get("/api/v1/projects", headers=auth_headers(admin_tokens))
    assert response.status_code == 200
    payload = response.json()
    assert "result" in payload
    assert "count" in payload
    assert isinstance(payload["result"], list)


def _create_project(client, admin_tokens, auth_headers, year=2026, branch_id=1) -> tuple[int, str]:
    name = f"PT_{uuid.uuid4().hex[:10]}"
    response = client.post(
        "/api/v1/projects",
        json={"name": name, "year": year, "branch_id": branch_id},
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 200
    payload = response.json()
    return payload["project_id"], name


def _add_line(client, admin_tokens, auth_headers, project_id: int, year: int = 2026) -> int:
    for expense_item_id in range(1, 80):
        response = client.post(
            f"/api/v1/projects/{project_id}/report/{year}/LIMIT/line",
            json={"expense_item_id": expense_item_id},
            headers=auth_headers(admin_tokens),
        )
        if response.status_code != 200:
            continue
        rows = response.json()
        input_row = next(
            (
                row
                for row in rows
                if row.get("row_type") == "INPUT" and row.get("data", {}).get("line_id")
            ),
            None,
        )
        if input_row:
            return int(input_row["data"]["line_id"])

    pytest.skip("Не удалось подобрать expense_item_id для add_form3_line в текущей БД")


def test_create_project_smoke(client, admin_tokens, auth_headers):
    name = f"PT_{uuid.uuid4().hex[:10]}"
    response = client.post(
        "/api/v1/projects",
        json={"name": name, "year": None, "branch_id": 1},
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 200
    payload = response.json()
    assert "project_id" in payload
    assert (project_id := payload["project_id"]) is not None
    response = client.get(
        f"/api/v1/projects/{project_id}",
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 200
    payload = response.json()
    assert "result" in payload
    assert "id" in payload["result"]
    assert payload["result"]["id"] == project_id
    assert "years" in payload["result"]
    assert isinstance(payload["result"]["years"], list)
    assert len(payload["result"]["years"]) == 1


def test_projects_write_smoke(client, admin_tokens, auth_headers):
    project_id, name = _create_project(client, admin_tokens, auth_headers)

    upd_project_response = client.patch(
        f"/api/v1/project/{project_id}",
        json={"column": "name", "value": f"{name}_U"},
        headers=auth_headers(admin_tokens),
    )
    assert upd_project_response.status_code == 200

    line_id = _add_line(client, admin_tokens, auth_headers, project_id)

    upd_cell_response = client.patch(
        f"/api/v1/projects/{project_id}/report/2026/LIMIT/cell",
        json={"line_id": line_id, "column": "q1.m1", "value": 100},
        headers=auth_headers(admin_tokens),
    )

    assert upd_cell_response.status_code == 200
    assert isinstance(upd_cell_response.json(), list)

    upd_cells_response = client.patch(
        f"/api/v1/projects/{project_id}/report/2026/LIMIT/cells",
        json={
            "changes": [
                {"line_id": line_id, "column": "q1.m2", "value": 200},
                {"line_id": line_id, "column": "q1.m3", "value": 300},
            ]
        },
        headers=auth_headers(admin_tokens),
    )
    assert upd_cells_response.status_code == 200
    assert isinstance(upd_cells_response.json(), list)

    del_line_response = client.delete(
        f"/api/v1/projects/{project_id}/report/2026/LIMIT/line/{line_id}",
        headers=auth_headers(admin_tokens),
    )
    assert del_line_response.status_code == 200


def test_projects_write_invalid_report_type_error_shape(client, admin_tokens, auth_headers):
    project_id, _ = _create_project(client, admin_tokens, auth_headers)
    line_id = _add_line(client, admin_tokens, auth_headers, project_id)

    response = client.patch(
        f"/api/v1/projects/{project_id}/report/2026/BAD_TYPE/cell",
        json={"line_id": line_id, "column": "q1.m1", "value": 100},
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 400
    payload = response.json()
    assert isinstance(payload, dict)
    assert "message" in payload
    assert isinstance(payload["message"], str)


def test_projects_write_report_not_found_error_shape(client, admin_tokens, auth_headers):
    project_id, _ = _create_project(client, admin_tokens, auth_headers)
    line_id = _add_line(client, admin_tokens, auth_headers, project_id)

    response = client.patch(
        f"/api/v1/projects/{project_id}/report/2099/LIMIT/cell",
        json={"line_id": line_id, "column": "q1.m1", "value": 100},
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 400
    payload = response.json()
    assert isinstance(payload, dict)
    assert payload.get("message") == "Отчёт не найден"


def test_delete_project_smoke(client, admin_tokens, auth_headers):
    project_id, _ = _create_project(client, admin_tokens, auth_headers, year=datetime.now().year)

    response = client.delete(
        f"/api/v1/projects/{project_id}",
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 200
    payload = response.json()
    assert payload["success"] is True
    assert payload["message"] == "Проект удалён"


def test_delete_project_verify_gone(client, admin_tokens, auth_headers):
    project_id, _ = _create_project(client, admin_tokens, auth_headers, year=datetime.now().year)

    del_response = client.delete(
        f"/api/v1/projects/{project_id}",
        headers=auth_headers(admin_tokens),
    )
    assert del_response.status_code == 200

    get_response = client.get(
        f"/api/v1/projects/{project_id}",
        headers=auth_headers(admin_tokens),
    )
    assert get_response.status_code == 404


def test_delete_project_not_found(client, admin_tokens, auth_headers):
    response = client.delete(
        "/api/v1/projects/99999",
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 400
    payload = response.json()
    assert isinstance(payload, dict)
    assert "message" in payload


def test_delete_project_unauthorized(client):
    response = client.delete("/api/v1/projects/1")
    assert response.status_code == 403

#ToDo: вернуть, когда пофиксим смещение фаз в зависимости от года
# def test_delete_project_with_lines_blocked(client, admin_tokens, auth_headers):
#     """Проект со строками отчёта нельзя удалить: can_delete_project → false → RAISE EXCEPTION."""
#     year = datetime.now().year - 1
#     project_id, _ = _create_project(client, admin_tokens, auth_headers, year=year)
#     _add_line(client, admin_tokens, auth_headers, project_id, year=year)

#     response = client.delete(
#         f"/api/v1/projects/{project_id}",
#         headers=auth_headers(admin_tokens),
#     )
#     assert response.status_code == 400
#     payload = response.json()
#     assert isinstance(payload, dict)
#     assert "code" in payload
#     assert "message" in payload
#     assert "невозможно удалить" in payload["message"]


def test_delete_project_executor_from_other_org(client, admin_tokens, auth_headers, isp_tokens):
    """ISP1 (привязан к РФ id=2) не может удалить проект на ССП id=1 — ACL."""
    project_id, _ = _create_project(client, admin_tokens, auth_headers, branch_id=1, year=datetime.now().year)

    response = client.delete(
        f"/api/v1/projects/{project_id}",
        headers=auth_headers(isp_tokens),
    )
    assert response.status_code == 400
    payload = response.json()
    assert "message" in payload
    assert payload["message"] == "Проект не найден"


#ToDo: вернуть, когда пофиксим смещение фаз в зависимости от года
# def test_delete_project_executor_from_same_org(client, isp_tokens, auth_headers):
#     """ISP1 может удалить проект на своём РФ (id=2), если нет строк отчёта."""
#     project_id = _create_project(client, isp_tokens, auth_headers, branch_id=2, year=datetime.now().year)

#     response = client.delete(
#         f"/api/v1/projects/{project_id}",
#         headers=auth_headers(isp_tokens),
#     )
#     assert response.status_code == 200
#     payload = response.json()
#     assert payload["success"] is True
#     assert payload["message"] == "Проект удалён"


def test_delete_seed_project_smoke(client, admin_tokens, auth_headers):
    """Проект из фикстуры (id=2) удаляется: у него нет строк отчёта, can_delete_project → true."""
    response = client.delete(
        "/api/v1/projects/2",
        headers=auth_headers(admin_tokens),
    )
    assert response.status_code == 200
    payload = response.json()
    assert payload["success"] is True
    assert payload["message"] == "Проект удалён"
