from fastapi import HTTPException

from .signal_analysis import simple_signal_info, get_audio

from .frame_analysis import (
    simple_frame_info,
    calculate_frame_f1_f2,
    validate_frame_index,
)
from .error_rates import calculate_error_rates
from .types import FileStateType, DatabaseType
import tempfile
import subprocess
from typing import Any


def simple_info_mode(
    database: DatabaseType, file_state: FileStateType
) -> dict[str, Any]:
    """
    Extracts and returns basic information about a signal and its corresponding frame.

    This function combines the signal information, file metadata, and frame-specific details.

    Parameters:
    - database: The database object used to fetch the file.
    - file_state: A dictionary containing the state of the file, including frame indices.

    Returns:
    - dict: A dictionary containing the combined signal information, file size, file creation date,
            and frame information. If the frame index is invalid, it still includes the basic file information.

    Example:
    ```python
    result = simple_info_mode(database, file_state)
    ```
    """

    file = get_file(database, file_state)

    audio = get_audio(file)

    result = simple_signal_info(audio)

    result["fileSize"] = len(file["data"])
    result["fileCreationDate"] = file["creationTime"]

    frame_index = validate_frame_index(audio.get_array_of_samples(), file_state)

    result["frame"] = simple_frame_info(
        audio.get_array_of_samples(), audio.frame_rate, frame_index
    )

    return result


def spectrogram_mode(database: DatabaseType, file_state: FileStateType) -> Any:
    """
    TBD
    """
    return None


def waveform_mode(database: DatabaseType, file_state: FileStateType) -> Any:
    """
    TBD
    """
    return None


def vowel_space_mode(
    database: DatabaseType, file_state: FileStateType
) -> dict[str, float] | None:
    """
    Extracts and returns the first and second formants of a specified frame.

    This function calculates the first (f1) and second (f2) formants of a segment within the audio signal.

    Parameters:
    - database: The database object used to fetch the file.
    - file_state: A dictionary containing the state of the file, including frame indices.

    Returns:
    - dict: A dictionary containing the first formant (f1) and the second formant (f2).
    - Returns None if the frame index is invalid.

    Example:
    ```python
    result = vowel_space_mode(database, file_state)
    ```
    """

    file = get_file(database, file_state)
    audio = get_audio(file)
    data = audio.get_array_of_samples()
    frame_index = validate_frame_index(data, file_state)

    if frame_index is None:
        return None

    frame_data = data[frame_index["startIndex"] : frame_index["endIndex"]]
    formants = calculate_frame_f1_f2(frame_data, audio.frame_rate)
    return {"f1": formants[0], "f2": formants[1]}


def transcription_mode(database: DatabaseType, file_state: FileStateType) -> Any:
    """
    TBD
    """
    return None


def error_rate_mode(
    database: DatabaseType, file_state: FileStateType
) -> dict[str, Any] | None:
    """
    Calculate the error rates of transcriptions against the ground truth.

    Parameters:
    - database: The database object used to fetch the file.
    - file_state: A dictionary containing the state of the file, including transcriptions.

    Returns:
    - A dictionary with the ground truth and a list of error rates for each transcription.
    - Returns None if there are no transcriptions or if the ground truth is missing.

    Example:
    ```python
    result = error_rate_mode(database, file_state)
    ```
    """
    if (
        "reference" not in file_state
        or file_state["reference"] is None
        or "captions" not in file_state["reference"]
        or file_state["reference"]["captions"] is None
        or "hypothesis" not in file_state
        or file_state["hypothesis"] is None
        or "captions" not in file_state["hypothesis"]
        or file_state["hypothesis"]["captions"] is None
    ):
        return None

    errorRate = calculate_error_rates(
        file_state["reference"]["captions"], file_state["hypothesis"]["captions"]
    )

    return errorRate


def get_file(database: DatabaseType, file_state: FileStateType) -> FileStateType:
    """
    Fetch a file from the database using the file_state information.

    Parameters:
    - database: The database object used to fetch the file.
    - file_state: A dictionary containing the state of the file, including its ID.

    Returns:
    - The file object fetched from the database.

    Raises:
    - HTTPException: If the 'id' is not in file_state or if the file is not found.

    Example:
    ```python
    file = get_file(database, file_state)
    ```
    """
    if "id" not in file_state:
        raise HTTPException(status_code=404, detail="file_state did not include id")
    try:
        print(file_state["id"])
        print(database)
        file = database.fetch_file(file_state["id"])  # pyright: ignore[reportAttributeAccessIssue]
    except Exception as _:
        raise HTTPException(status_code=404, detail="File not found")

    file["data"] = convert_to_wav(file["data"])

    return file


def convert_to_wav(data: bytes) -> bytes:
    with tempfile.NamedTemporaryFile(delete=False) as temp_input:
        temp_input.write(data)
        temp_input.flush()  # Ensure data is written to disk
        with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_output:
            command = ["ffmpeg", "-y", "-i", temp_input.name, temp_output.name]
            subprocess.run(command, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
            temp_output.seek(0)  # Rewind to the beginning of the file
            return temp_output.read()
