import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_NUM_CHANNELS, CONF_SAMPLE_RATE
import esphome.final_validate as fv

CODEOWNERS = ["@kahrendt"]
audio_ns = cg.esphome_ns.namespace("audio")

AudioFile = audio_ns.struct("AudioFile")
AudioFileType = audio_ns.enum("AudioFileType", is_class=True)
AUDIO_FILE_TYPE_ENUM = {
    "NONE": AudioFileType.NONE,
    "WAV": AudioFileType.WAV,
    "MP3": AudioFileType.MP3,
    "FLAC": AudioFileType.FLAC,
}


CONF_MIN_BITS_PER_SAMPLE = "min_bits_per_sample"
CONF_MAX_BITS_PER_SAMPLE = "max_bits_per_sample"
CONF_MIN_CHANNELS = "min_channels"
CONF_MAX_CHANNELS = "max_channels"
CONF_MIN_SAMPLE_RATE = "min_sample_rate"
CONF_MAX_SAMPLE_RATE = "max_sample_rate"


CONFIG_SCHEMA = cv.All(
    cv.Schema({}),
)

AUDIO_COMPONENT_SCHEMA = cv.Schema(
    {
        cv.Optional(CONF_BITS_PER_SAMPLE): cv.int_range(8, 32),
        cv.Optional(CONF_NUM_CHANNELS): cv.int_range(1, 2),
        cv.Optional(CONF_SAMPLE_RATE): cv.int_range(8000, 48000),
    }
)


_UNDEF = object()


def set_stream_limits(
    min_bits_per_sample: int = _UNDEF,
    max_bits_per_sample: int = _UNDEF,
    min_channels: int = _UNDEF,
    max_channels: int = _UNDEF,
    min_sample_rate: int = _UNDEF,
    max_sample_rate: int = _UNDEF,
):
    def set_limits_in_config(config):
        if min_bits_per_sample is not _UNDEF:
            config[CONF_MIN_BITS_PER_SAMPLE] = min_bits_per_sample
        if max_bits_per_sample is not _UNDEF:
            config[CONF_MAX_BITS_PER_SAMPLE] = max_bits_per_sample
        if min_channels is not _UNDEF:
            config[CONF_MIN_CHANNELS] = min_channels
        if max_channels is not _UNDEF:
            config[CONF_MAX_CHANNELS] = max_channels
        if min_sample_rate is not _UNDEF:
            config[CONF_MIN_SAMPLE_RATE] = min_sample_rate
        if max_sample_rate is not _UNDEF:
            config[CONF_MAX_SAMPLE_RATE] = max_sample_rate

    return set_limits_in_config


def final_validate_audio_schema(
    name: str,
    *,
    audio_device: str,
    bits_per_sample: int,
    channels: int,
    sample_rate: int,
):
    def validate_audio_compatiblity(audio_config):
        audio_schema = {}

        try:
            cv.int_range(
                min=audio_config.get(CONF_MIN_BITS_PER_SAMPLE),
                max=audio_config.get(CONF_MAX_BITS_PER_SAMPLE),
            )(bits_per_sample)
        except cv.Invalid as exc:
            raise cv.Invalid(
                f"Invalid configuration for the {name} component. The {CONF_BITS_PER_SAMPLE} {str(exc)}"
            ) from exc

        try:
            cv.int_range(
                min=audio_config.get(CONF_MIN_CHANNELS),
                max=audio_config.get(CONF_MAX_CHANNELS),
            )(channels)
        except cv.Invalid as exc:
            raise cv.Invalid(
                f"Invalid configuration for the {name} component. The {CONF_NUM_CHANNELS} {str(exc)}"
            ) from exc

        try:
            cv.int_range(
                min=audio_config.get(CONF_MIN_SAMPLE_RATE),
                max=audio_config.get(CONF_MAX_SAMPLE_RATE),
            )(sample_rate)
            return cv.Schema(audio_schema, extra=cv.ALLOW_EXTRA)(audio_config)
        except cv.Invalid as exc:
            raise cv.Invalid(
                f"Invalid configuration for the {name} component. The {CONF_SAMPLE_RATE} {str(exc)}"
            ) from exc

    return cv.Schema(
        {
            cv.Required(audio_device): fv.id_declaration_match_schema(
                validate_audio_compatiblity
            )
        },
        extra=cv.ALLOW_EXTRA,
    )


async def to_code(config):
    cg.add_library("esphome/esp-audio-libs", "1.1.3")
