from __future__ import annotations

import os
import re
import time
from typing import Any

import pytest

from .helpers import ReleaseApiClient


def _select_rule_set(client: ReleaseApiClient) -> dict[str, Any]:
    preferred_rule_type = os.getenv("LEAUDIT_TEST_RULE_TYPE", "contract.entrust").strip()
    rule_sets = ReleaseApiClient.json_data(client.get("/api/rule-sets"))
    assert isinstance(rule_sets, list)
    assert rule_sets, "当前环境没有规则集，无法测试版本管理"

    for item in rule_sets:
        if str(item.get("ruleType") or "") == preferred_rule_type and item.get("currentVersionId"):
            return item

    for item in rule_sets:
        if item.get("currentVersionId"):
            return item

    pytest.skip("当前环境没有带 currentVersionId 的规则集，无法测试发布/回滚闭环")


def _set_metadata_version(yaml_text: str, version_no: str) -> str:
    lines = yaml_text.splitlines()
    metadata_index: int | None = None
    version_pattern = re.compile(r"^(\s*)version\s*:")

    for index, line in enumerate(lines):
        if line.strip() == "metadata:":
            metadata_index = index
            continue
        if metadata_index is None:
            continue
        if line and not line.startswith((" ", "\t")):
            break
        match = version_pattern.match(line)
        if match:
            lines[index] = f"{match.group(1)}version: '{version_no}'"
            return "\n".join(lines) + ("\n" if yaml_text.endswith("\n") else "")

    if metadata_index is None:
        return f"metadata:\n  version: '{version_no}'\n{yaml_text}"

    lines.insert(metadata_index + 1, f"  version: '{version_no}'")
    return "\n".join(lines) + ("\n" if yaml_text.endswith("\n") else "")


def _rule_set_by_type(client: ReleaseApiClient, rule_type: str) -> dict[str, Any]:
    rule_sets = ReleaseApiClient.json_data(client.get("/api/rule-sets"))
    for item in rule_sets:
        if str(item.get("ruleType") or "") == rule_type:
            return item
    raise AssertionError(f"规则集不存在: {rule_type}")


@pytest.mark.release
def test_g6_rule_detail_version_management_save_publish_and_rollback(admin_client: ReleaseApiClient) -> None:
    """覆盖规则配置详情页的版本管理闭环。

    该用例会创建一个真实历史版本并短暂发布，最后回滚到执行前的 currentVersionId。
    """

    target_rule_set = _select_rule_set(admin_client)
    rule_type = str(target_rule_set["ruleType"])
    original_rule_set_id = int(target_rule_set["id"])
    original_current_version_id = int(target_rule_set["currentVersionId"])
    original_tenant_code = str(target_rule_set.get("effectiveTenantCode") or "")

    versions_before = ReleaseApiClient.json_data(admin_client.get(f"/api/rule-sets/{rule_type}/versions"))
    assert isinstance(versions_before, list)
    assert {int(item["ruleSetId"]) for item in versions_before} == {original_rule_set_id}
    assert original_current_version_id in {int(item["id"]) for item in versions_before}

    content = ReleaseApiClient.json_data(admin_client.get(f"/api/rule-sets/versions/{original_current_version_id}/content"))
    assert int(content["ruleSetId"]) == original_rule_set_id
    assert str(content["ruleType"]) == rule_type
    assert str(content["yamlText"]).strip()

    new_version_no = f"pytest-vm-{int(time.time())}"
    yaml_text = _set_metadata_version(str(content["yamlText"]), new_version_no)
    created_version_id: int | None = None

    try:
        created = ReleaseApiClient.json_data(
            admin_client.post(
                f"/api/rule-sets/{rule_type}/versions",
                json={
                    "yamlText": yaml_text,
                    "changeNote": f"pytest rule detail version management smoke {new_version_no}",
                },
                expected_status=200,
            )
        )
        created_version_id = int(created["id"])
        assert int(created["ruleSetId"]) == original_rule_set_id
        assert str(created["versionNo"]) == new_version_no
        assert str(created["status"]) == "draft"

        versions_after_create = ReleaseApiClient.json_data(admin_client.get(f"/api/rule-sets/{rule_type}/versions"))
        assert created_version_id in {int(item["id"]) for item in versions_after_create}
        assert {int(item["ruleSetId"]) for item in versions_after_create} == {original_rule_set_id}

        published = ReleaseApiClient.json_data(
            admin_client.post(
                f"/api/rule-sets/{rule_type}/publish",
                json={"versionId": created_version_id},
                expected_status=200,
            )
        )
        assert int(published["id"]) == created_version_id
        assert int(published["ruleSetId"]) == original_rule_set_id
        assert str(published["status"]) == "published"

        current_after_publish = _rule_set_by_type(admin_client, rule_type)
        assert int(current_after_publish["id"]) == original_rule_set_id
        assert int(current_after_publish["currentVersionId"]) == created_version_id
        assert str(current_after_publish.get("effectiveTenantCode") or "") == original_tenant_code

    finally:
        if created_version_id:
            admin_client.post(
                f"/api/rule-sets/{rule_type}/rollback",
                json={"versionId": original_current_version_id},
                expected_status=200,
            )

    restored = _rule_set_by_type(admin_client, rule_type)
    assert int(restored["id"]) == original_rule_set_id
    assert int(restored["currentVersionId"]) == original_current_version_id
    assert str(restored.get("effectiveTenantCode") or "") == original_tenant_code


@pytest.mark.release
def test_g6_rule_detail_version_management_rejects_cross_rule_set_publish(admin_client: ReleaseApiClient) -> None:
    """发布接口必须拒绝把其他规则集的版本发布到当前规则类型。"""

    rule_sets = ReleaseApiClient.json_data(admin_client.get("/api/rule-sets"))
    candidates = [item for item in rule_sets if item.get("currentVersionId")]
    if len(candidates) < 2:
        pytest.skip("当前环境少于两个带 currentVersionId 的规则集，无法测试跨规则集发布拦截")

    left = candidates[0]
    right = next((item for item in candidates[1:] if str(item["ruleType"]) != str(left["ruleType"])), None)
    if right is None:
        pytest.skip("当前环境没有可用于跨规则类型发布拦截的第二个规则集")

    response = admin_client.post(
        f"/api/rule-sets/{left['ruleType']}/publish",
        json={"versionId": int(right["currentVersionId"])},
        expected_status=403,
    )
    assert "当前租户不能发布或回滚其他租户的规则版本" in response.text
