from __future__ import annotations

import zipfile
from pathlib import Path
from types import SimpleNamespace

import pytest

from app.tools.oci_audio_download import (
    _parse_date,
    _parse_session_id,
    download_prefix,
    entire_calls_prefix,
    segments_prefix,
)
from app.utils.stt_audio_upload import OCIUploadConfig


class _Raw:
    def __init__(self, content: bytes) -> None:
        self.content = content

    def stream(self, _size: int, decode_content: bool = False):
        assert decode_content is False
        yield self.content


class _Client:
    def __init__(self, objects: dict[str, bytes]) -> None:
        self.objects = objects
        self.downloaded: list[str] = []

    def list_objects(self, **kwargs):
        prefix = kwargs["prefix"]
        items = [
            SimpleNamespace(name=name, size=len(content), etag="etag")
            for name, content in self.objects.items()
            if name.startswith(prefix)
        ]
        return SimpleNamespace(data=SimpleNamespace(objects=items, next_start_with=None))

    def get_object(self, **kwargs):
        name = kwargs["object_name"]
        self.downloaded.append(name)
        return SimpleNamespace(data=SimpleNamespace(raw=_Raw(self.objects[name])))


def _config() -> OCIUploadConfig:
    return OCIUploadConfig("local", "sa-saopaulo-1", "tia-audio", "namespace")


def test_prefixes_match_object_storage_layout() -> None:
    assert segments_prefix("2026-07-24", "session-123") == "2026-07-24/session-123/"
    assert entire_calls_prefix("2026-07-24") == "2026-07-24/entire_call/"


def test_argument_validation() -> None:
    assert _parse_date("2026-07-24") == "2026-07-24"
    assert _parse_session_id("session_123") == "session_123"
    with pytest.raises(Exception):
        _parse_date("24/07/2026")
    with pytest.raises(Exception):
        _parse_session_id("../entire_call")


def test_download_prefix_downloads_and_creates_zip(tmp_path: Path) -> None:
    prefix = "2026-07-24/entire_call/"
    client = _Client(
        {
            f"{prefix}call-a.wav": b"audio-a",
            f"{prefix}call-b.wav": b"audio-b",
            "2026-07-23/entire_call/old.wav": b"old",
        }
    )
    output_dir = tmp_path / "calls"
    zip_path = tmp_path / "calls.zip"
    result = download_prefix(
        client=client,
        config=_config(),
        prefix=prefix,
        output_dir=output_dir,
        zip_path=zip_path,
    )
    assert result.object_count == 2
    assert result.downloaded_count == 2
    assert (output_dir / "call-a.wav").read_bytes() == b"audio-a"
    with zipfile.ZipFile(zip_path) as archive:
        assert sorted(archive.namelist()) == ["call-a.wav", "call-b.wav"]
        assert archive.testzip() is None


def test_download_prefix_reuses_complete_file(tmp_path: Path) -> None:
    prefix = "2026-07-24/session-123/"
    name = f"{prefix}message.wav"
    client = _Client({name: b"segment"})
    output_dir = tmp_path / "segments"
    output_dir.mkdir()
    (output_dir / "message.wav").write_bytes(b"segment")
    result = download_prefix(
        client=client,
        config=_config(),
        prefix=prefix,
        output_dir=output_dir,
        zip_path=None,
    )
    assert result.cached_count == 1
    assert result.downloaded_count == 0
    assert client.downloaded == []


def test_download_prefix_rejects_empty_prefix(tmp_path: Path) -> None:
    with pytest.raises(FileNotFoundError):
        download_prefix(
            client=_Client({}),
            config=_config(),
            prefix="2026-07-24/entire_call/",
            output_dir=tmp_path,
            zip_path=None,
        )
