use std::pin::Pin;

use crate::packet::{Audio, AudioCodec};
use anyhow::{Result, bail};
use bytes::Bytes;

use th_rs::define::{TH_AUDIOCODECTYPE_TH_ACT_G711, TH_DATATYPE_TH_DT_AUDIO, TH_ESStreamInfo};
use tokio::task::block_in_place;

#[cfg(feature = "enable_codec")]
use xodec_rs::encoder_aac::EncoderAAC;

pub(crate) struct AACEncoder {
    #[cfg(feature = "enable_codec")]
    encoder: Pin<Box<EncoderAAC>>,
}

impl AACEncoder {
    pub fn new() -> Self {
        #[cfg(feature = "enable_codec")]
        {
            Self {
                encoder: EncoderAAC::new(),
            }
        }
        #[cfg(not(feature = "enable_codec"))]
        {
            Self {}
        }
    }
    #[allow(unused_variables)]
    pub fn write(&mut self, audio: &Audio, payload: Bytes) -> Result<Bytes> {
        #[cfg(feature = "enable_codec")]
        {
            let encoder = &mut self.encoder;
            match audio.codec {
                AudioCodec::Aac => Ok(payload),
                AudioCodec::G711A => {
                    let o_aac = block_in_place(move || {
                        let sp = tracing::span!(tracing::Level::ERROR, "aac_encode");
                        let _enter = sp.enter();
                        encoder.write(
                            &payload,
                            &TH_ESStreamInfo {
                                streamType: TH_DATATYPE_TH_DT_AUDIO as _,
                                aCodecType: TH_AUDIOCODECTYPE_TH_ACT_G711 as _,
                                aSampleRate: audio.sample_rate,
                                aChannels: audio.channels,
                                aSampleBits: audio.bits,
                                ..Default::default()
                            },
                        )
                    });

                    let Ok(aac) = o_aac else { bail!("Encode aac fail") };

                    Ok(Bytes::copy_from_slice(aac))
                },
                other => bail!("No support audio codec({:?}) encode to aac", other),
            }
        }
        #[cfg(not(feature = "enable_codec"))]
        {
            const ERR_MSG: &str = "enable_codec feature is not enabled, cannot encode audio";
            tracing::error!("{ERR_MSG}");
            bail!(ERR_MSG)
        }
    }
}