#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
音频数据块管理类 - 用于存储和处理16KHz音频数据
"""

from typing import List, Optional, Dict
from src.models import AudioBinary_Config, AudioBinary_data_list

# 配置日志
from src.utils.logger import get_module_logger

logger = get_module_logger(__name__, level="INFO")


class AudioBinary:
    """
    音频数据存储单元
    用于存储二进制数据
    面向Slice, 向Slice提供数据与接口

    self._audio_config: AudioBinary_Config -- 音频参数配置
    self._binary_data_list: AudioBinary_data_list -- 音频数据列表
    self._slice_listener: List[callable] -- 切片监听器

    AudioBinary_Config: Dict -- 音频参数配置
    AudioBinary_data_list: List[bytes] -- 音频数据列表
    """

    def __init__(self, *args):
        """
        初始化音频数据块
        参数:
            *args: 可变参数
        """
        # 音频参数配置
        self._audio_config = AudioBinary_Config()
        # 音频片段
        self._binary_data_list: AudioBinary_data_list = AudioBinary_data_list()
        # 切片监听器
        self._slice_listener: List = []
        if isinstance(args, Dict):
            self._audio_config = AudioBinary_Config.AudioBinary_Config_from_dict(args)
        elif isinstance(args, AudioBinary_Config):
            self._audio_config = args
        else:
            raise ValueError("参数类型错误")

    def add_slice_listener(self, slice_listener: callable) -> None:
        """
        添加切片监听器
        参数:
            slice_listener: callable -- 切片监听器
        """
        self._slice_listener.append(slice_listener)

    def __add__(self, other: bytes):
        """
        __add__ 是 "+" 运算符的重载，
        使用方法:
            audio_binary = audio_binary + bytes
        添加音频数据块 与 add_binary_data 等效，
        但可以链式调用, 方便使用
        参数:
            other: bytes --音频数据块
        """
        self._binary_data_list.append(other)
        return self

    def __iadd__(self, other: bytes):
        """
        __iadd__ 是 "+=" 运算符的重载，
        使用方法:
            audio_binary += bytes
        添加音频数据块 与 add_binary_data 等效，
        但可以链式调用, 方便使用
        参数:
            other: bytes --音频数据块
        """
        self._binary_data_list.append(other)
        return self

    def add_binary_data(self, binary_data: bytes):
        """
        添加音频数据块
        参数:
            binary_data: bytes --音频数据块
        """
        self._binary_data_list.append(binary_data)

    def rewrite_binary_data(self, target_index: int, binary_data: bytes):
        """
        重写音频数据块
        参数:
            target_index: int -- 目标索引
            binary_data: bytes --音频数据块
        """
        self._binary_data_list.rewrite(target_index, binary_data)

    def get_binary_data(
        self,
        start: int = 0,
        end: Optional[int] = None,
    ) -> Optional[bytes]:
        """
        获取指定索引的音频数据块
        参数:
            start: 开始索引
            end: 结束索引
        返回:
            List[bytes]: 音频数据块
        """
        if start >= len(self._binary_data_list):
            return None
        if end is None:
            end = start + 1
        end = min(end, len(self._binary_data_list))
        return self._binary_data_list[start:end]


class AudioChunk:
    """
    音频数据块管理类
    管理两部分内容, AudioBinary和Slice。
    AudioBinary用于内部存储字节数据。
    Slice是AudioBinary的切片,用于外部接口。

    此类仅用于AudioBinary与Funtor的交互, 不负责其它逻辑。
    """

    _instance: Optional[AudioChunk] = None

    def __new__(cls, *args, **kwargs):
        """
        单例模式
        """
        if cls._instance is None:
            cls._instance = super(AudioChunk, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self) -> None:
        """
        初始化AudioChunk实例
        """
        self._audio_binary_list: Dict[str, AudioBinary] = {}
        self._slice_listener: List[callable] = []

    def get_audio_binary(
        self,
        binary_name: Optional[str] = None,
        audio_config: Optional[AudioBinary_Config] = None,
    ) -> AudioBinary:
        """
        获取音频数据块
        参数:
            binary_name: str -- 音频数据块名称
        返回:
            AudioBinary: 音频数据块
        """
        if binary_name is None:
            binary_name = "default"
        if binary_name not in self._audio_binary_list:
            self._audio_binary_list[binary_name] = AudioBinary(audio_config)
        return self._audio_binary_list[binary_name]

    @staticmethod
    def _time2size(time_ms: int, audio_config: AudioBinary_Config) -> int:
        """
        将时间(ms)转换为数据大小(字节)
        参数:
            time_ms: int -- 时间(ms)
            audio_config: AudioBinary_Config -- 音频参数配置
        返回:
            int: 数据大小(字节)
        """
        # 时间(ms)到字节(bytes)计算方法为: 时间(ms) * 采样率(Hz) * 通道数(1 or 2) * 采样位宽(16 or 24) / 1000
        time_s = time_ms / 1000
        bytes_per_sample = audio_config.sample_width * audio_config.channel
        return int(time_s * audio_config.sample_rate * bytes_per_sample)

    @staticmethod
    def _size2time(size: int, audio_config: AudioBinary_Config) -> int:
        """
        将数据大小(字节)转换为时间(ms)
        参数:
            size: int -- 数据大小(字节)
            audio_config: AudioBinary_Config -- 音频参数配置
        返回:
            int: 时间(ms)
        """
        # 字节(bytes)到时间(ms)计算方法为: 字节(bytes) * 1000 / (采样率(Hz) * 通道数(1 or 2) * 采样位宽(16 or 24))
        bytes_per_sample = audio_config.sample_width * audio_config.channel
        time_ms = size * 1000 // (audio_config.sample_rate * bytes_per_sample)
        return time_ms
