"""Tests for mgf-cloud credential/config loading (Pass 2)."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from mgf.cloud.config import CloudConfig, from_clouds_yaml, from_env, load
from mgf.cloud.exceptions import CredentialsError

if TYPE_CHECKING:
    from pathlib import Path

APPCRED_YAML = """
clouds:
  openstack:
    auth:
      auth_url: https://api.pub1.infomaniak.cloud/identity/v3
      application_credential_id: APPID
      application_credential_secret: APPSECRET
    region_name: dc3-a
    interface: public
    identity_api_version: 3
"""


def _write(tmp_path: Path, text: str, name: str = "clouds.yaml") -> Path:
    path = tmp_path / name
    path.write_text(text, encoding="utf-8")
    return path


def test_from_clouds_yaml_application_credential(tmp_path: Path) -> None:
    creds = from_clouds_yaml(_write(tmp_path, APPCRED_YAML))
    assert creds.auth_url.endswith("/identity/v3")
    assert creds.region_name == "dc3-a"
    assert creds.has_app_credential
    assert creds.auth_type == "v3applicationcredential"
    assert creds.application_credential_secret is not None
    assert creds.application_credential_secret.get_secret_value() == "APPSECRET"


def test_secret_is_not_leaked_in_repr(tmp_path: Path) -> None:
    creds = from_clouds_yaml(_write(tmp_path, APPCRED_YAML))
    assert "APPSECRET" not in repr(creds)
    assert "APPSECRET" not in str(creds)


def test_missing_file_raises_with_source(tmp_path: Path) -> None:
    with pytest.raises(CredentialsError) as excinfo:
        from_clouds_yaml(tmp_path / "absent.yaml")
    assert excinfo.value.source is not None


def test_unknown_cloud_raises(tmp_path: Path) -> None:
    with pytest.raises(CredentialsError):
        from_clouds_yaml(_write(tmp_path, APPCRED_YAML), cloud="other")


def test_incomplete_credentials_name_missing(tmp_path: Path) -> None:
    bad = "clouds:\n  openstack:\n    auth:\n      auth_url: https://x/identity/v3\n"
    with pytest.raises(CredentialsError) as excinfo:
        from_clouds_yaml(_write(tmp_path, bad))
    assert excinfo.value.missing


def test_from_env_application_credential() -> None:
    creds = from_env(
        {
            "OS_AUTH_URL": "https://api.pub1.infomaniak.cloud/identity/v3",
            "OS_REGION_NAME": "dc3-a",
            "OS_APPLICATION_CREDENTIAL_ID": "id",
            "OS_APPLICATION_CREDENTIAL_SECRET": "sec",
        }
    )
    assert creds.has_app_credential
    assert creds.region_name == "dc3-a"


def test_from_env_missing_auth_url() -> None:
    with pytest.raises(CredentialsError):
        from_env({})


def test_load_prefers_explicit_path(tmp_path: Path) -> None:
    creds = load(clouds_yaml=_write(tmp_path, APPCRED_YAML), environ={})
    assert creds.has_app_credential


def test_load_uses_env_when_no_path() -> None:
    creds = load(
        environ={
            "OS_AUTH_URL": "https://x/identity/v3",
            "OS_USERNAME": "u",
            "OS_PASSWORD": "p",
            "OS_PROJECT_ID": "proj",
        }
    )
    assert creds.has_password
    assert creds.auth_type == "v3password"


def test_load_honours_env_override(tmp_path: Path) -> None:
    path = _write(tmp_path, APPCRED_YAML)
    creds = load(environ={"MGF_CLOUD_CLOUDS_YAML": str(path)})
    assert creds.has_app_credential


def test_load_raises_when_nothing_found(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr("mgf.cloud.config._default_clouds_yaml_paths", tuple)
    with pytest.raises(CredentialsError):
        load(environ={})


def test_cloudconfig_load(tmp_path: Path) -> None:
    cfg = CloudConfig.load(
        provider="infomaniak", clouds_yaml=_write(tmp_path, APPCRED_YAML), environ={}
    )
    assert cfg.provider == "infomaniak"
    assert cfg.credentials.has_app_credential
