//! Radio Paradise UPnP Media Server implementation

use crate::error::{Error, Result};
use crate::models::Bitrate;
use crate::RadioParadiseClient;
use pmoserver::Server;
use pmoupnp::devices::Device;
use pmoupnp::UpnpServer;
use std::sync::Arc;
use tokio::sync::RwLock;

/// Radio Paradise UPnP Media Server
///
/// Exposes Radio Paradise blocks and songs as a browsable UPnP media library.
pub struct RadioParadiseMediaServer {
    server: Server,
    client: Arc<RwLock<RadioParadiseClient>>,
    device_udn: String,
}

impl RadioParadiseMediaServer {
    /// Create a new builder for the media server
    pub fn builder() -> MediaServerBuilder {
        MediaServerBuilder::default()
    }

    /// Create a new media server with default settings
    pub async fn new() -> Result<Self> {
        Self::builder().build().await
    }

    /// Run the media server
    ///
    /// This will start the HTTP server and SSDP announcements.
    pub async fn run(self) -> Result<()> {
        self.server
            .run()
            .await
            .map_err(|e| Error::other(format!("Server error: {}", e)))
    }

    /// Get the device UDN
    pub fn udn(&self) -> &str {
        &self.device_udn
    }

    /// Get the Radio Paradise client
    pub fn client(&self) -> Arc<RwLock<RadioParadiseClient>> {
        self.client.clone()
    }
}

/// Builder for RadioParadiseMediaServer
pub struct MediaServerBuilder {
    friendly_name: String,
    manufacturer: String,
    model_name: String,
    bitrate: Bitrate,
    channel: u8,
    port: u16,
}

impl Default for MediaServerBuilder {
    fn default() -> Self {
        Self {
            friendly_name: "Radio Paradise Media Server".to_string(),
            manufacturer: "PMOMusic".to_string(),
            model_name: "Radio Paradise Adapter".to_string(),
            bitrate: Bitrate::Flac,
            channel: 0,
            port: 8080,
        }
    }
}

impl MediaServerBuilder {
    /// Create a new builder with default settings
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the friendly name for the device
    pub fn with_friendly_name(mut self, name: impl Into<String>) -> Self {
        self.friendly_name = name.into();
        self
    }

    /// Set the manufacturer name
    pub fn with_manufacturer(mut self, name: impl Into<String>) -> Self {
        self.manufacturer = name.into();
        self
    }

    /// Set the model name
    pub fn with_model_name(mut self, name: impl Into<String>) -> Self {
        self.model_name = name.into();
        self
    }

    /// Set the bitrate/quality level
    pub fn with_bitrate(mut self, bitrate: Bitrate) -> Self {
        self.bitrate = bitrate;
        self
    }

    /// Set the Radio Paradise channel (0=main, 1=mellow, 2=rock, 3=world)
    pub fn with_channel(mut self, channel: u8) -> Self {
        self.channel = channel;
        self
    }

    /// Set the HTTP server port
    pub fn with_port(mut self, port: u16) -> Self {
        self.port = port;
        self
    }

    /// Build the media server
    pub async fn build(self) -> Result<RadioParadiseMediaServer> {
        // Create Radio Paradise client
        let client = RadioParadiseClient::builder()
            .bitrate(self.bitrate)
            .channel(self.channel)
            .build()
            .await?;

        let client = Arc::new(RwLock::new(client));

        // Create HTTP server
        let mut server = pmoserver::ServerBuilder::new()
            .with_port(self.port)
            .build()
            .map_err(|e| Error::other(format!("Failed to create server: {}", e)))?;

        // Create UPnP device
        let device_udn = format!("uuid:{}", uuid::Uuid::new_v4());

        let mut device = Device::new(
            "MediaServer".to_string(),
            "MediaServer".to_string(),
            self.friendly_name.clone(),
        );

        device.set_manufacturer(self.manufacturer);
        device.set_model_name(self.model_name);
        device.set_udn(device_udn.clone());

        // Add ContentDirectory service
        let content_directory =
            super::content_directory::create_content_directory_service(client.clone());
        device
            .add_service(Arc::new(content_directory))
            .map_err(|e| Error::other(format!("Failed to add ContentDirectory: {:?}", e)))?;

        // Add ConnectionManager service
        let connection_manager = super::connection_manager::create_connection_manager_service();
        device
            .add_service(Arc::new(connection_manager))
            .map_err(|e| Error::other(format!("Failed to add ConnectionManager: {:?}", e)))?;

        // Register device with server
        server
            .register_device(Arc::new(device))
            .await
            .map_err(|e| Error::other(format!("Failed to register device: {:?}", e)))?;

        Ok(RadioParadiseMediaServer {
            server,
            client,
            device_udn,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_builder_defaults() {
        let builder = MediaServerBuilder::default();
        assert_eq!(builder.friendly_name, "Radio Paradise Media Server");
        assert_eq!(builder.bitrate, Bitrate::Flac);
        assert_eq!(builder.channel, 0);
        assert_eq!(builder.port, 8080);
    }

    #[test]
    fn test_builder_customization() {
        let builder = MediaServerBuilder::new()
            .with_friendly_name("Custom Server")
            .with_bitrate(Bitrate::Aac320)
            .with_channel(1)
            .with_port(9090);

        assert_eq!(builder.friendly_name, "Custom Server");
        assert_eq!(builder.bitrate, Bitrate::Aac320);
        assert_eq!(builder.channel, 1);
        assert_eq!(builder.port, 9090);
    }
}
