from __future__ import annotations

import sys
import types
from datetime import datetime

from app.utils import stt_audio_upload
from app.utils.stt_audio_upload import (
    build_stt_vad_object_name,
    enqueue_stt_vad_audio_upload,
)


_BUCKET_ENV_NAMES = (
    "OCI_AUTH_MODE",
    "BUCKET_USER_ID",
    "BUCKET_PRIVATE_KEY",
    "BUCKET_FINGERPRINT",
    "BUCKET_TENANCY_ID",
    "BUCKET_REGION",
    "BUCKET_NAME",
    "BUCKET_NAMESPACE",
)


def _clear_bucket_env(monkeypatch) -> None:
    for name in _BUCKET_ENV_NAMES:
        monkeypatch.delenv(name, raising=False)


def _install_fake_oci_modules(monkeypatch) -> dict[str, object]:
    calls: dict[str, object] = {}

    class FakeObjectStorageClient:
        def __init__(self, config, **kwargs) -> None:
            calls["client_config"] = config
            calls["client_kwargs"] = kwargs

    def fake_oke_signer() -> object:
        signer = object()
        calls["signer"] = signer
        return signer

    fake_oci = types.ModuleType("oci")
    fake_auth = types.ModuleType("oci.auth")
    fake_signers = types.ModuleType("oci.auth.signers")
    fake_object_storage = types.ModuleType("oci.object_storage")

    fake_object_storage.ObjectStorageClient = FakeObjectStorageClient
    fake_signers.get_oke_workload_identity_resource_principal_signer = fake_oke_signer
    fake_auth.signers = fake_signers
    fake_oci.auth = fake_auth
    fake_oci.object_storage = fake_object_storage

    monkeypatch.setitem(sys.modules, "oci", fake_oci)
    monkeypatch.setitem(sys.modules, "oci.auth", fake_auth)
    monkeypatch.setitem(sys.modules, "oci.auth.signers", fake_signers)
    monkeypatch.setitem(sys.modules, "oci.object_storage", fake_object_storage)
    return calls


def _reset_oci_client_cache(monkeypatch) -> None:
    monkeypatch.setattr(stt_audio_upload, "_OCI_CLIENT", None)
    monkeypatch.setattr(stt_audio_upload, "_OCI_CLIENT_CONFIG", None)


def test_stt_vad_object_name_uses_requested_layout_and_stays_short() -> None:
    object_name = build_stt_vad_object_name(
        session_id="sessao muito longa/" * 30,
        message_id="message-id-muito-longo/" * 30,
        req_id="req-id-muito-longo/" * 30,
        now=datetime(2026, 6, 24, 13, 52, 21),
    )

    parts = object_name.split("/")
    assert parts[0] == "2026-06-24"
    assert object_name.endswith(".wav")
    assert len(parts) == 3
    assert len(object_name.encode("utf-8")) <= 512
    assert all(len(part) <= 68 for part in parts[1:])
    assert " " not in object_name


def test_stt_vad_object_name_uses_message_id_as_filename() -> None:
    object_name = build_stt_vad_object_name(
        session_id="417a5a59-961a-4ba6-9c68-71e92a3da46d",
        message_id="0bc6875e-ebd1-4dca-a43d-2f7de404895b",
        req_id="c182775c8c114e3f833bfb7675e0be70",
        now=datetime(2026, 6, 29, 10, 30, 0),
    )

    assert (
        object_name
        == "2026-06-29/417a5a59-961a-4ba6-9c68-71e92a3da46d/"
        "0bc6875e-ebd1-4dca-a43d-2f7de404895b.wav"
    )
    assert "c182775c8c114e3f833bfb7675e0be70" not in object_name


def test_oci_upload_config_reads_bucket_env_and_private_key(monkeypatch) -> None:
    _clear_bucket_env(monkeypatch)
    monkeypatch.setenv("OCI_AUTH_MODE", "local")
    monkeypatch.setenv("BUCKET_USER_ID", "user-ocid")
    monkeypatch.setenv("BUCKET_PRIVATE_KEY", "-----BEGIN KEY-----\\nabc\\n-----END KEY-----")
    monkeypatch.setenv("BUCKET_FINGERPRINT", "fingerprint")
    monkeypatch.setenv("BUCKET_TENANCY_ID", "tenancy-ocid")
    monkeypatch.setenv("BUCKET_REGION", "sa-saopaulo-1")
    monkeypatch.setenv("BUCKET_NAME", "tia-audio")
    monkeypatch.setenv("BUCKET_NAMESPACE", "namespace")

    config = stt_audio_upload._oci_upload_config_from_env()

    assert config is not None
    assert config.auth_mode == "local"
    assert config.bucket == "tia-audio"
    assert config.namespace == "namespace"
    assert config.key_content == "-----BEGIN KEY-----\nabc\n-----END KEY-----"


def test_oci_upload_config_uses_oke_when_auth_mode_is_absent(monkeypatch) -> None:
    _clear_bucket_env(monkeypatch)
    monkeypatch.setenv("BUCKET_REGION", "sa-saopaulo-1")
    monkeypatch.setenv("BUCKET_NAME", "tia-audio")
    monkeypatch.setenv("BUCKET_NAMESPACE", "namespace")

    config = stt_audio_upload._oci_upload_config_from_env()

    assert config is not None
    assert config.auth_mode == "oke_workload_identity"
    assert config.bucket == "tia-audio"
    assert config.namespace == "namespace"
    assert config.user == ""
    assert config.key_content == ""


def test_oci_upload_config_uses_oke_when_auth_mode_is_not_local(monkeypatch) -> None:
    _clear_bucket_env(monkeypatch)
    monkeypatch.setenv("OCI_AUTH_MODE", "prd")
    monkeypatch.setenv("BUCKET_REGION", "sa-saopaulo-1")
    monkeypatch.setenv("BUCKET_NAME", "tia-audio")
    monkeypatch.setenv("BUCKET_NAMESPACE", "namespace")

    config = stt_audio_upload._oci_upload_config_from_env()

    assert config is not None
    assert config.auth_mode == "oke_workload_identity"


def test_oci_upload_config_is_missing_when_local_required_env_is_absent(monkeypatch) -> None:
    _clear_bucket_env(monkeypatch)
    monkeypatch.setenv("OCI_AUTH_MODE", "local")
    monkeypatch.setenv("BUCKET_REGION", "sa-saopaulo-1")
    monkeypatch.setenv("BUCKET_NAME", "tia-audio")
    monkeypatch.setenv("BUCKET_NAMESPACE", "namespace")

    assert stt_audio_upload._oci_upload_config_from_env() is None


def test_oci_upload_config_is_missing_when_oke_required_env_is_absent(monkeypatch) -> None:
    _clear_bucket_env(monkeypatch)
    monkeypatch.setenv("BUCKET_REGION", "sa-saopaulo-1")
    monkeypatch.setenv("BUCKET_NAME", "tia-audio")

    assert stt_audio_upload._oci_upload_config_from_env() is None


def test_oci_client_uses_api_key_config_for_local_mode(monkeypatch) -> None:
    _reset_oci_client_cache(monkeypatch)
    calls = _install_fake_oci_modules(monkeypatch)
    config = stt_audio_upload.OCIUploadConfig(
        auth_mode="local",
        region="sa-saopaulo-1",
        bucket="tia-audio",
        namespace="namespace",
        user="user-ocid",
        key_content="private-key",
        fingerprint="fingerprint",
        tenancy="tenancy-ocid",
    )

    stt_audio_upload._oci_client(config)

    assert calls["client_config"] == {
        "user": "user-ocid",
        "key_content": "private-key",
        "fingerprint": "fingerprint",
        "tenancy": "tenancy-ocid",
        "region": "sa-saopaulo-1",
    }
    assert calls["client_kwargs"] == {}
    assert "signer" not in calls


def test_oci_client_uses_oke_signer_for_workload_identity(monkeypatch) -> None:
    _reset_oci_client_cache(monkeypatch)
    calls = _install_fake_oci_modules(monkeypatch)
    config = stt_audio_upload.OCIUploadConfig(
        auth_mode="oke_workload_identity",
        region="sa-saopaulo-1",
        bucket="tia-audio",
        namespace="namespace",
    )

    stt_audio_upload._oci_client(config)

    assert calls["client_config"] == {"region": "sa-saopaulo-1"}
    assert calls["client_kwargs"] == {"signer": calls["signer"]}


def test_enqueue_stt_vad_audio_upload_is_noop_without_oci_config(monkeypatch) -> None:
    monkeypatch.setattr(stt_audio_upload, "_oci_upload_config_from_env", lambda: None)

    assert (
        enqueue_stt_vad_audio_upload(
            wav_bytes=b"fake-wav",
            req_id="req-1",
            message_id="message-1",
            structured_log_context={"session_id": "session-1"},
        )
        is None
    )
