import base64
import hmac
from hashlib import sha256
from unittest.mock import Mock
from urllib.parse import parse_qs, urlparse

from botocore.exceptions import ClientError
import pytest

from dsg_core.core.config import BucketStorageSettings
from dsg_core.core import s3


def test_generate_signed_url_custom_domain_uses_download_hmac_secret(monkeypatch):
    monkeypatch.setattr(
        s3.settings.bucket_storage,
        "public_download_url",
        "https://core-downloads.local.datasdrapps.com",
    )
    monkeypatch.setattr(
        s3.settings.bucket_storage,
        "download_hmac_secret",
        "sc+HqbWm48Xhplzm+bYJmuYvDGj2W5rhBW6Wue2NUyw=",
    )
    monkeypatch.setattr(s3.time, "time", lambda: 1_777_458_771)

    url = s3.generate_signed_url(
        "dsg-core/reports/0030d435-a283-5ff4-ba01-c1d28bbbcfa7/Codelists_20260427.csv",
        "local-dev",
        file_name="my report.csv",
        content_type="text/csv",
    )

    parsed_url = urlparse(url)
    query = parse_qs(parsed_url.query)
    expected_signing_payload = (
        "/dsg-core/reports/0030d435-a283-5ff4-ba01-c1d28bbbcfa7/"
        "Codelists_20260427.csv1777462371"
    )
    expected_signature = base64.b64encode(
        hmac.new(
            b"sc+HqbWm48Xhplzm+bYJmuYvDGj2W5rhBW6Wue2NUyw=",
            expected_signing_payload.encode("utf-8"),
            sha256,
        ).digest()
    ).decode("ascii")

    assert parsed_url.scheme == "https"
    assert parsed_url.netloc == "core-downloads.local.datasdrapps.com"
    assert (
        parsed_url.path == "/dsg-core/reports/0030d435-a283-5ff4-ba01-c1d28bbbcfa7/"
        "Codelists_20260427.csv"
    )
    assert query == {"verify": [f"1777462371-{expected_signature}"]}


def test_bucket_storage_ssl_verify_defaults_to_true_for_blank_values() -> None:
    settings = BucketStorageSettings.model_validate({"ssl_verify": ""})
    assert settings.ssl_verify is True


def test_bucket_storage_ssl_verify_parses_false_string() -> None:
    settings = BucketStorageSettings.model_validate({"ssl_verify": "false"})
    assert settings.ssl_verify is False


def test_bucket_storage_ssl_verify_preserves_ca_bundle_path() -> None:
    settings = BucketStorageSettings.model_validate(
        {"ssl_verify": "/etc/ssl/local-r2-ca.pem"}
    )
    assert settings.ssl_verify == "/etc/ssl/local-r2-ca.pem"


def test_get_s3_verify_uses_bucket_storage_setting(monkeypatch) -> None:
    monkeypatch.setattr(
        s3.settings.bucket_storage,
        "ssl_verify",
        "/etc/ssl/local-r2-ca.pem",
    )
    assert s3._get_s3_verify() == "/etc/ssl/local-r2-ca.pem"


def test_upload_bytes_logs_client_error_context(monkeypatch) -> None:
    error = ClientError(
        {
            "Error": {"Code": "500", "Message": "Internal Server Error"},
            "ResponseMetadata": {
                "HTTPStatusCode": 500,
                "RequestId": "req-123",
                "HostId": "host-456",
                "RetryAttempts": 4,
            },
        },
        "PutObject",
    )

    monkeypatch.setattr(
        s3.settings.bucket_storage,
        "url",
        "https://example.r2.cloudflarestorage.com",
    )
    monkeypatch.setattr(s3.settings.bucket_storage, "ssl_verify", False)
    monkeypatch.setattr(
        s3.s3_client,
        "put_object",
        Mock(side_effect=error),
    )
    exception_log = Mock()
    monkeypatch.setattr(s3.logger, "exception", exception_log)

    with pytest.raises(ClientError):
        s3.upload_bytes(
            b"abc",
            bucket="local-dev",
            key="dsg-core/reports/job/report.csv",
            content_type="text/csv",
        )

    exception_log.assert_called_once()
    message, bucket, key, content_type, size, context = exception_log.call_args.args
    assert "Bucket upload failed" in message
    assert bucket == "local-dev"
    assert key == "dsg-core/reports/job/report.csv"
    assert content_type == "text/csv"
    assert size == 3
    assert context["error_code"] == "500"
    assert context["http_status_code"] == 500
    assert context["request_id"] == "req-123"
    assert context["host_id"] == "host-456"
    assert context["retry_attempts"] == 4
    assert context["endpoint_url"] == "https://example.r2.cloudflarestorage.com"
    assert context["ssl_verify"] is False
