from fastapi.testclient import TestClient

from app.main import app, get_pulp_client

client = TestClient(app)

VH = "/pulp/api/v3/repositories/rpm/rpm/abc/versions/3/"
REPO = {"name": "rocky9-baseos", "repo_config": {"gpgcheck": 1, "repo-gpgcheck": 1}}
VERSIONS = [
    {
        "pulp_href": "/pulp/api/v3/repositories/rpm/rpm/abc/versions/2/",
        "content_summary": {"present": {"rpm.package": {"count": 4700}}},
    },
    {
        "pulp_href": VH,
        "content_summary": {"present": {"rpm.package": {"count": 4821}}},
    },
]
DISTRIBUTIONS = [
    {
        "pulp_href": "/pulp/api/v3/distributions/rpm/rpm/dabc/",
        "publication": "/pulp/api/v3/publications/rpm/rpm/abc-2/",
    }
]
PUBLICATIONS = {
    "/pulp/api/v3/publications/rpm/rpm/abc-2/": {
        "repository_version": "/pulp/api/v3/repositories/rpm/rpm/abc/versions/2/"
    }
}


class _FakePulp:
    def __init__(
        self,
        repo=None,
        distributions=None,
        pub_state="completed",
        dist_state="completed",
        pub_created=True,
    ):
        self._repo = REPO if repo is None else repo
        self._distributions = DISTRIBUTIONS if distributions is None else distributions
        self._pub_state = pub_state
        self._dist_state = dist_state
        self._pub_created = pub_created
        self.created_with = None
        self.dist_args = None

    def get_repo(self, uuid):
        return self._repo

    def list_versions(self, uuid):
        return VERSIONS

    def list_distributions(self):
        return self._distributions

    def get_publication(self, href):
        return PUBLICATIONS.get(href, {})

    def create_publication(self, version_href):
        self.created_with = version_href
        return "/pulp/api/v3/tasks/pub/"

    def update_distribution(self, dist_href, publication_href):
        self.dist_args = (dist_href, publication_href)
        return "/pulp/api/v3/tasks/dist/"

    def wait_for_task(self, task_href, attempts=120, delay=1.0):
        if "pub" in task_href:
            created = (
                ["/pulp/api/v3/publications/rpm/rpm/new/"] if self._pub_created else []
            )
            return {"state": self._pub_state, "created_resources": created}
        return {"state": self._dist_state, "created_resources": []}


def _use(fake):
    app.dependency_overrides[get_pulp_client] = lambda: fake


def teardown_function():
    app.dependency_overrides.clear()


def _post(confirm_name):
    return client.post(
        "/repos/abc/deploy",
        data={"version_href": VH, "confirm_name": confirm_name},
    )


def test_confirm_modal_shows_preview_and_type_to_confirm():
    _use(_FakePulp())
    resp = client.get("/repos/abc/deploy/confirm", params={"version_href": VH})
    assert resp.status_code == 200
    body = resp.text
    assert "운영망에 배포" in body
    assert "rocky9-baseos" in body  # type-to-confirm 대상 이름
    assert "배포 확정" in body
    assert "+121" in body  # 4821 - 4700 미리보기


def test_deploy_blocked_when_not_verified():
    _use(_FakePulp(repo={"name": "r", "repo_config": {"gpgcheck": 0}}))
    resp = client.post(
        "/repos/abc/deploy", data={"version_href": VH, "confirm_name": "r"}
    )
    assert resp.status_code == 403
    assert "검증" in resp.text


def test_deploy_rejects_name_mismatch():
    _use(_FakePulp())
    resp = _post("wrong-name")
    assert resp.status_code == 400
    assert "이름이 일치" in resp.text


def test_deploy_requires_existing_distribution():
    _use(_FakePulp(distributions=[]))
    resp = _post("rocky9-baseos")
    assert resp.status_code == 404
    assert "distribution" in resp.text


def test_deploy_publication_failure_keeps_prod_unchanged():
    _use(_FakePulp(pub_state="failed"))
    resp = _post("rocky9-baseos")
    assert resp.status_code == 502
    assert "운영망은 변경되지 않았습니다" in resp.text


def test_deploy_distribution_failure_reported():
    _use(_FakePulp(dist_state="failed"))
    resp = _post("rocky9-baseos")
    assert resp.status_code == 502
    assert "운영망 변경에 실패" in resp.text


def test_deploy_success_writes_audit_and_refreshes_list(monkeypatch):
    # 감사 DB 쓰기는 _write 를 가로채 캡처(실 DB 불필요)
    records = []
    monkeypatch.setattr("app.audit._write", lambda entry: records.append(entry))

    fake = _FakePulp()
    _use(fake)
    resp = _post("rocky9-baseos")
    assert resp.status_code == 200
    assert "배포 완료" in resp.text
    assert 'hx-swap-oob="true"' in resp.text  # 버전 목록 OOB 갱신

    # publication 은 대상 버전으로, distribution 은 새 publication 으로 교체
    assert fake.created_with == VH
    assert fake.dist_args == (
        "/pulp/api/v3/distributions/rpm/rpm/dabc/",
        "/pulp/api/v3/publications/rpm/rpm/new/",
    )

    # 감사 기록: from=2, to=3, repo 이름
    assert len(records) == 1
    assert records[0]["from_version"] == 2
    assert records[0]["to_version"] == 3
    assert records[0]["repo_name"] == "rocky9-baseos"


def test_deploy_succeeds_but_flags_when_audit_fails(monkeypatch):
    def _boom(entry):
        raise RuntimeError("DATABASE_URL 미설정")

    monkeypatch.setattr("app.audit._write", _boom)
    _use(_FakePulp())
    resp = _post("rocky9-baseos")
    # 배포는 이미 완료 → 200 이되, 감사 기록 실패를 UI 에 경고
    assert resp.status_code == 200
    assert "배포 완료" in resp.text
    assert "감사 로그 기록 실패" in resp.text
