//! Channel messaging bindings for Rust
//! Provides functions to list channels, read messages, and send messages by channel name

use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE};
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ChannelError {
    #[error("HTTP request failed: {0}")]
    RequestError(#[from] reqwest::Error),
    #[error("Channel not found: {0}")]
    ChannelNotFound(String),
    #[error("Invalid header value")]
    InvalidHeader,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel {
    pub id: String,
    pub name: String,
    #[serde(flatten)]
    pub extra: serde_json::Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
    pub id: String,
    pub content: String,
    #[serde(alias = "channelId", alias = "channel_id")]
    pub channel_id: String,
    pub timestamp: Option<String>,
    pub author: Option<String>,
    #[serde(flatten)]
    pub extra: serde_json::Value,
}

#[derive(Debug, Serialize)]
struct SendMessagePayload {
    content: String,
}

pub struct ChannelClient {
    url: String,
    client: Client,
}

impl ChannelClient {
    pub fn new(url: &str, token: &str) -> Result<Self, ChannelError> {
        let mut headers = HeaderMap::new();
        headers.insert(
            AUTHORIZATION,
            HeaderValue::from_str(&format!("Bearer {}", token))
                .map_err(|_| ChannelError::InvalidHeader)?,
        );
        headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));

        let client = Client::builder().default_headers(headers).build()?;

        Ok(Self {
            url: url.trim_end_matches('/').to_string(),
            client,
        })
    }

    /// List all available channels
    pub fn list_channels(&self) -> Result<Vec<Channel>, ChannelError> {
        let response = self
            .client
            .get(format!("{}/channels", self.url))
            .send()?
            .error_for_status()?;

        Ok(response.json()?)
    }

    /// Find a channel ID by its name
    pub fn find_channel_id_by_name(&self, name: &str) -> Result<Option<String>, ChannelError> {
        let channels = self.list_channels()?;
        Ok(channels.into_iter().find(|c| c.name == name).map(|c| c.id))
    }

    /// Read channel details by name
    pub fn read_channel(&self, name: &str) -> Result<Option<Channel>, ChannelError> {
        let channels = self.list_channels()?;
        Ok(channels.into_iter().find(|c| c.name == name))
    }

    /// Read messages from a channel by name
    pub fn read_messages(
        &self,
        channel_name: &str,
        limit: Option<u32>,
    ) -> Result<Vec<Message>, ChannelError> {
        let channel_id = self
            .find_channel_id_by_name(channel_name)?
            .ok_or_else(|| ChannelError::ChannelNotFound(channel_name.to_string()))?;

        let mut url = format!("{}/channels/{}/messages", self.url, channel_id);
        if let Some(limit) = limit {
            url.push_str(&format!("?limit={}", limit));
        }

        let response = self.client.get(&url).send()?.error_for_status()?;

        Ok(response.json()?)
    }

    /// Send a message to a channel by name
    pub fn send_message(&self, channel_name: &str, content: &str) -> Result<Message, ChannelError> {
        let channel_id = self
            .find_channel_id_by_name(channel_name)?
            .ok_or_else(|| ChannelError::ChannelNotFound(channel_name.to_string()))?;

        let payload = SendMessagePayload {
            content: content.to_string(),
        };

        let response = self
            .client
            .post(format!("{}/channels/{}/messages", self.url, channel_id))
            .json(&payload)
            .send()?
            .error_for_status()?;

        Ok(response.json()?)
    }
}

/// Create a new channel client
pub fn create_client(url: &str, token: &str) -> Result<ChannelClient, ChannelError> {
    ChannelClient::new(url, token)
}

/// List all available channels
pub fn list_channels(url: &str, token: &str) -> Result<Vec<Channel>, ChannelError> {
    create_client(url, token)?.list_channels()
}

/// Read channel details by name
pub fn read_channel(url: &str, token: &str, name: &str) -> Result<Option<Channel>, ChannelError> {
    create_client(url, token)?.read_channel(name)
}

/// Read messages from a channel by name
pub fn read_messages(
    url: &str,
    token: &str,
    channel_name: &str,
    limit: Option<u32>,
) -> Result<Vec<Message>, ChannelError> {
    create_client(url, token)?.read_messages(channel_name, limit)
}

/// Send a message to a channel by name
pub fn send_message(
    url: &str,
    token: &str,
    channel_name: &str,
    content: &str,
) -> Result<Message, ChannelError> {
    create_client(url, token)?.send_message(channel_name, content)
}
