"""
Tests for the utility module
"""

import sys
from pathlib import Path
from unittest.mock import patch

sys.path.append("/Users/ayushranjan/Documents/Redenlab/Git_projects/redenlab-extract/src")

import numpy as np
import pytest

from redenlab_extract.exceptions import ValidationError
from redenlab_extract.utils import (
    get_content_type,
    split_audio_into_chunks,
    validate_api_key_format,
)

# --- Happy path: exact mappings ---


@pytest.mark.parametrize(
    "filename, expected",
    [
        ("clip.wav", "audio/wav"),
        ("clip.wave", "audio/wav"),
        ("clip.flac", "audio/flac"),
        ("clip.ogg", "audio/ogg"),
    ],
)
def test_get_content_type_supported(filename, expected):
    assert get_content_type(filename) == expected


# --- Case-insensitivity + funky names ---


@pytest.mark.parametrize(
    "filename, expected",
    [
        ("UPPER.WAV", "audio/wav"),
        ("mix.cAsE.fLaC", "audio/flac"),
        ("speace name.ogg", "audio/ogg"),
        ("multiple.dots.name.WAVE", "audio/wav"),
    ],
)
def test_get_content_type_is_case_sensitive_and_handles_multiple_dots(filename, expected):
    assert get_content_type(filename) == expected


# --- Unsupported extensions raise ValidationError ---


@pytest.mark.parametrize("filename", ["song.mp3", "audio.m4a", "noext", "weird.ext"])
def test_get_content_type_unsupported(filename):
    with pytest.raises(ValidationError):
        get_content_type(filename)


####### validate_api_key_format #######

# --- Happy path: correct keys ---


@pytest.mark.parametrize(
    "api_key",
    ["A8531V9AfBaCyVaU3WXV25AjYb0eCb4aaDggfs5s", "hagHjkeUyN67IOJBabdkifn7842JbjslI8Hlksnf"],
)
def test_api_key_format_supported(api_key):
    assert validate_api_key_format(api_key) is None


# --- small + empty + long + with whitespaces---


@pytest.mark.parametrize(
    "api_key",
    [
        "jYb0eCb4a",
        "",
        " A8531V9AfBaCyVaU3WXV25AjYb0eCb4aaDggfs5s",
        "hagHjkeUyN67IOJBabdkifn7842JbjslI8Hlksnf ",
    ],
)
def test_api_key_format_is_small_and_empty_and_has_whitespaces_raises(api_key):
    with pytest.raises(ValidationError):
        validate_api_key_format(api_key)


def test_api_key_format_long_raises():
    api_key = "x" * 101
    with pytest.raises(ValidationError):
        validate_api_key_format(api_key)


####### split_audio_into_chunks #######


def make_fake_audio(duration_seconds: float, samplerate: int = 16000):
    """Create fake audio data of specified duration."""
    return np.zeros(int(samplerate * duration_seconds)), samplerate


@pytest.fixture
def audio_mocks():
    """Fixture that sets up soundfile and validate_file_path mocks."""
    with (
        patch("soundfile.read") as mock_read,
        patch("redenlab_extract.utils.validate_file_path") as mock_validate,
    ):
        mock_validate.return_value = Path("test_audio.wav")
        yield mock_read, mock_validate


def test_split_audio_no_split_when_shorter_than_chunk_duration(audio_mocks):
    """Audio shorter than chunk_duration returns empty list."""
    mock_read, _ = audio_mocks
    mock_read.return_value = make_fake_audio(duration_seconds=30)

    result = split_audio_into_chunks("anything_audio.wav", chunk_duration=60)

    assert result == []


def test_split_audio_no_split_when_equal_to_chunk_duration(audio_mocks):
    mock_read, _ = audio_mocks
    mock_read.return_value = make_fake_audio(duration_seconds=60)

    result = split_audio_into_chunks("anything_audio.wav", chunk_duration=60)
    assert result == []


def test_split_audio_yes_split_when_greater_than_chunk_duration(audio_mocks):
    """Audio longer than the chunk duration produces correct output."""
    mock_read, _ = audio_mocks
    mock_read.return_value = make_fake_audio(duration_seconds=120)

    result = split_audio_into_chunks("anything_audio.wav", chunk_duration=60)
    # All are paths
    assert all(isinstance(p, (str, Path)) for p in result)
    # With 120s audio, 60s chunks, 1s overlap → expect 3 chunks
    assert len(result) == 3
    # Assert naming
    assert all("redenlab_audio_chunks_" in p for p in result)


# def test_split_audio_chunks_overlap_correctly(audio_mocks):
#     """Consecutive chunks share overlapping samples."""
#     mock_read, _ = audio_mocks
#     sample_rate =16000

#     mock_read.return_value = np.arrange(sample_rate*120, dtype=np.float32)


def test_split_audio_raises_validation_error_for_bad_file(audio_mocks):
    """Non-existent file raises ValidationError."""
    _, mock_validate = audio_mocks
    mock_validate.side_effect = ValidationError("File not found.")

    with pytest.raises(ValidationError):
        split_audio_into_chunks("nonexistant.wav")


def test_split_audio_raises_validation_error_for_corrupted_file(audio_mocks):
    """Corrupted/invalid audio file raises ValidationError."""
    mock_read, _ = audio_mocks
    mock_read.side_effect = Exception("Failed to read audio file")

    with pytest.raises(ValidationError, match="Failed to split audio file"):
        split_audio_into_chunks("corrupted.wav")


def test_split_audio_raises_import_error_when_soundfile_missing():
    """Missing soundfile library raises ImportError."""
    with patch.dict("sys.modules", {"soundfile": None}):
        with pytest.raises(ImportError, match="soundfile and numpy are required"):
            split_audio_into_chunks("test.wav")
