//! TCP 服务端：监听端口、接收设备连接、按 LF 分割 JSON 消息。

use futures::StreamExt;
use std::time::Duration;
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::mpsc;
use tokio::time;
use tokio_util::codec::{FramedRead, LinesCodec};

use super::connection::{ConnectionPool, DeviceConnection};
use super::handler::handle_message;
use super::protocol::DeviceMessage;

/// 心跳超时：5000ms 未收到消息则断开连接。
const HEARTBEAT_TIMEOUT: Duration = Duration::from_millis(5000);
/// 清理超时连接的间隔。
const CLEANUP_INTERVAL: Duration = Duration::from_secs(10);

/// 启动 TCP 监听循环。
pub async fn run_tcp_server(
    addr: String,
    pool: ConnectionPool,
    redis: redis::aio::ConnectionManager,
) {
    let listener = TcpListener::bind(&addr)
        .await
        .expect("TCP 端口绑定失败");
    tracing::info!("TCP 设备服务启动: {}", addr);

    // 后台清理过期连接
    let cleanup_pool = pool.clone();
    tokio::spawn(async move {
        let mut interval = time::interval(CLEANUP_INTERVAL);
        loop {
            interval.tick().await;
            let removed = cleanup_pool.cleanup_timeout(HEARTBEAT_TIMEOUT).await;
            for dev_id in &removed {
                tracing::warn!("[心跳超时] 断开 dev_id={}", dev_id);
            }
        }
    });

    loop {
        match listener.accept().await {
            Ok((stream, peer)) => {
                tracing::info!("[新连接] peer={}", peer);
                let pool = pool.clone();
                let redis = redis.clone();
                tokio::spawn(handle_connection(stream, peer, pool, redis));
            }
            Err(e) => {
                tracing::error!("accept 失败: {}", e);
            }
        }
    }
}

/// 处理单条 TCP 连接。
async fn handle_connection(
    stream: TcpStream,
    peer: std::net::SocketAddr,
    pool: ConnectionPool,
    redis: redis::aio::ConnectionManager,
) {
    let (reader, writer) = tokio::io::split(stream);
    let mut lines = FramedRead::new(reader, LinesCodec::new_with_max_length(4096));

    // 写通道：HTTP 命令下发通过此通道写入 TCP
    let (tx, mut rx) = mpsc::unbounded_channel::<String>();

    let mut current_dev_id: Option<String> = None;
    let mut writer = writer;

    loop {
        tokio::select! {
            // 读取设备消息
            line = lines.next() => {
                match line {
                    Some(Ok(text)) => {
                        if text.trim().is_empty() {
                            continue;
                        }

                        let msg: DeviceMessage = match serde_json::from_str(&text) {
                            Ok(m) => m,
                            Err(e) => {
                                tracing::warn!("[{}] JSON 解析失败: {} raw={}", peer, e, text);
                                continue;
                            }
                        };

                        // 如果是 login/auth_str，需要 dev_id 来关联连接
                        if (msg.act == "auth_str" || msg.act == "login")
                            && let Some(ref dev_id) = msg.dev_id
                                && current_dev_id.is_none() {
                                    let conn = DeviceConnection::new(dev_id.clone(), tx.clone());
                                    pool.register(dev_id.clone(), conn).await;
                                    current_dev_id = Some(dev_id.clone());
                                }

                        // 更新活跃时间
                        if let Some(ref dev_id) = current_dev_id {
                            pool.touch(dev_id).await;
                        }

                        // 处理消息
                        let resp = handle_message(msg, &pool, &redis).await;

                        if let Some(resp) = resp {
                            let json = resp.to_json();
                            if let Err(e) = tx.send(json) {
                                tracing::error!("[{}] 响应发送失败: {}", peer, e);
                                break;
                            }
                        }
                    }
                    Some(Err(e)) => {
                        tracing::warn!("[{}] 读取错误: {}", peer, e);
                        break;
                    }
                    None => {
                        tracing::info!("[{}] 连接关闭", peer);
                        break;
                    }
                }
            }
            // 向设备写指令
            Some(json) = rx.recv() => {
                use tokio::io::AsyncWriteExt;
                let framed = format!("{}\n", json);
                if let Err(e) = writer.write_all(framed.as_bytes()).await {
                    tracing::error!("[{}] 写入失败: {}", peer, e);
                    break;
                }
            }
        }
    }

    // 连接断开，清理
    if let Some(ref dev_id) = current_dev_id {
        pool.remove(dev_id).await;
        tracing::info!("[断连] dev_id={}", dev_id);
    }
}
