use base64::Engine;
use portable_pty::{native_pty_system, ChildKiller, CommandBuilder, MasterPty, PtySize};
use serde::Serialize;
use std::collections::{HashMap, VecDeque};
use std::io::{Read, Write};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex};
use tauri::{AppHandle, Emitter};

use crate::claude_path::resolve_claude_launcher;

#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PtyDataPayload {
    pub tab_id: String,
    pub data: String, // base64 编码的原始字节，前端用流式 TextDecoder 解码
}

#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PtyExitPayload {
    pub tab_id: String,
    pub exit_code: u32,
}

struct PtyEntry {
    master: Box<dyn MasterPty + Send>,
    writer: Box<dyn Write + Send>,
    killer: Box<dyn ChildKiller + Send + Sync>,
}

/// 移动端订阅者：一个已 attach 的 WS 连接对某 tab 字节流的通道
struct Subscriber {
    id: u64,
    tx: Sender<Vec<u8>>,
}

/// 每个 tab 原始字节回放环形缓冲上限（256KB），供移动端 attach/重连时重放当前屏。
/// 仅作「桌面序列化完整回看历史」不可用（会话未挂载等）时的兜底，主历史走序列化，无需太大。
const SCROLLBACK_CAP: usize = 256 * 1024;

/// 订阅 id 分配器
static SUB_SEQ: AtomicU64 = AtomicU64::new(1);

/// 管理所有终端会话：每个标签页对应一个跑着 claude 的 PTY
#[derive(Default, Clone)]
pub struct PtyManager {
    inner: Arc<Mutex<HashMap<String, PtyEntry>>>,
    /// tabId -> 订阅该 tab 字节流的移动端连接（数据面扇出）
    subscribers: Arc<Mutex<HashMap<String, Vec<Subscriber>>>>,
    /// tabId -> 原始字节环形缓冲（供移动端 attach/重连重放）
    scrollback: Arc<Mutex<HashMap<String, VecDeque<u8>>>>,
}

impl PtyManager {
    pub fn spawn(
        &self,
        app: AppHandle,
        tab_id: String,
        cwd: String,
        claude_args: Vec<String>,
        cols: u16,
        rows: u16,
        claude_path: &str,
    ) -> Result<(), String> {
        self.kill(&tab_id);

        let pty_system = native_pty_system();
        let pair = pty_system
            .openpty(PtySize {
                rows: if rows > 0 { rows } else { 24 },
                cols: if cols > 0 { cols } else { 80 },
                pixel_width: 0,
                pixel_height: 0,
            })
            .map_err(|e| e.to_string())?;

        let launcher = resolve_claude_launcher(claude_path);
        let mut cmd = CommandBuilder::new(&launcher.file);
        for a in &launcher.args_prefix {
            cmd.arg(a);
        }
        for a in &claude_args {
            cmd.arg(a);
        }
        cmd.cwd(&cwd);
        cmd.env("TERM", "xterm-256color");
        // 禁用每个会话的后台自动更新：多会话并发时彼此锁住 claude.exe，
        // 会触发 "claude.exe in use" 更新失败。改由设置页「立即更新」在无运行会话时集中手动更新。
        // 仅关闭后台自检，不影响手动 `claude update`。
        cmd.env("DISABLE_AUTOUPDATER", "1");

        let child = pair.slave.spawn_command(cmd).map_err(|e| e.to_string())?;
        drop(pair.slave);

        let killer = child.clone_killer();
        let mut reader = pair.master.try_clone_reader().map_err(|e| e.to_string())?;
        let writer = pair.master.take_writer().map_err(|e| e.to_string())?;

        {
            let mut map = self.inner.lock().unwrap();
            map.insert(
                tab_id.clone(),
                PtyEntry {
                    master: pair.master,
                    writer,
                    killer,
                },
            );
        }

        // 读线程：把 PTY 输出按字节流转发给桌面前端（emit）与移动端订阅者（扇出）
        let app_reader = app.clone();
        let tab_for_reader = tab_id.clone();
        let subscribers = self.subscribers.clone();
        let scrollback = self.scrollback.clone();
        std::thread::spawn(move || {
            let mut buf = [0u8; 16 * 1024];
            loop {
                match reader.read(&mut buf) {
                    Ok(0) | Err(_) => break,
                    Ok(n) => {
                        let chunk = &buf[..n];
                        // 原始字节写入环形缓冲，供移动端 attach/重连时重放当前屏
                        {
                            let mut sb = scrollback.lock().unwrap();
                            let ring = sb.entry(tab_for_reader.clone()).or_default();
                            ring.extend(chunk.iter().copied());
                            if ring.len() > SCROLLBACK_CAP {
                                let overflow = ring.len() - SCROLLBACK_CAP;
                                ring.drain(..overflow);
                            }
                        }
                        // 扇出给移动端订阅者：断开的连接顺手移除，绝不阻塞读线程
                        {
                            let mut subs = subscribers.lock().unwrap();
                            if let Some(list) = subs.get_mut(&tab_for_reader) {
                                list.retain(|s| s.tx.send(chunk.to_vec()).is_ok());
                                if list.is_empty() {
                                    subs.remove(&tab_for_reader);
                                }
                            }
                        }
                        // 转发给桌面前端（保持原样）
                        let data = base64::engine::general_purpose::STANDARD.encode(chunk);
                        let _ = app_reader.emit(
                            "pty-data",
                            PtyDataPayload {
                                tab_id: tab_for_reader.clone(),
                                data,
                            },
                        );
                    }
                }
            }
        });

        // 等待线程：进程退出后清理并通知前端
        let manager = self.clone();
        let mut child = child;
        std::thread::spawn(move || {
            let exit_code = child.wait().map(|s| s.exit_code()).unwrap_or(0);
            manager.remove(&tab_id);
            let _ = app.emit(
                "pty-exit",
                PtyExitPayload {
                    tab_id,
                    exit_code,
                },
            );
        });

        Ok(())
    }

    /// 移动端订阅某 tab 的字节流；返回订阅 id 与接收端（网关连接线程从中取字节转发）
    pub fn subscribe(&self, tab_id: &str) -> (u64, Receiver<Vec<u8>>) {
        let (tx, rx) = channel();
        let id = SUB_SEQ.fetch_add(1, Ordering::Relaxed);
        self.subscribers
            .lock()
            .unwrap()
            .entry(tab_id.to_string())
            .or_default()
            .push(Subscriber { id, tx });
        (id, rx)
    }

    /// 取消订阅（连接断开或 detach 时调用）
    pub fn unsubscribe(&self, tab_id: &str, id: u64) {
        let mut subs = self.subscribers.lock().unwrap();
        if let Some(list) = subs.get_mut(tab_id) {
            list.retain(|s| s.id != id);
            if list.is_empty() {
                subs.remove(tab_id);
            }
        }
    }

    /// 环形缓冲当前内容（原始字节），供移动端 attach/重连时重放
    pub fn snapshot(&self, tab_id: &str) -> Vec<u8> {
        self.scrollback
            .lock()
            .unwrap()
            .get(tab_id)
            .map(|r| r.iter().copied().collect())
            .unwrap_or_default()
    }

    /// 当前 CCGUI 拉起且仍存活的会话数（更新前的闸门判断用）
    pub fn active_count(&self) -> usize {
        self.inner.lock().unwrap().len()
    }

    pub fn write(&self, tab_id: &str, data: &str) {
        self.write_bytes(tab_id, data.as_bytes());
    }

    /// 写入原始字节（移动端 input 经 base64 解码后走此，避免 UTF-8 限制）
    pub fn write_bytes(&self, tab_id: &str, bytes: &[u8]) {
        let mut map = self.inner.lock().unwrap();
        if let Some(entry) = map.get_mut(tab_id) {
            let _ = entry.writer.write_all(bytes);
            let _ = entry.writer.flush();
        }
    }

    pub fn resize(&self, tab_id: &str, cols: u16, rows: u16) {
        if cols == 0 || rows == 0 {
            return;
        }
        let map = self.inner.lock().unwrap();
        if let Some(entry) = map.get(tab_id) {
            // PTY 可能刚退出，resize 失败可忽略
            let _ = entry.master.resize(PtySize {
                rows,
                cols,
                pixel_width: 0,
                pixel_height: 0,
            });
        }
    }

    fn remove(&self, tab_id: &str) {
        self.inner.lock().unwrap().remove(tab_id);
        self.subscribers.lock().unwrap().remove(tab_id);
        self.scrollback.lock().unwrap().remove(tab_id);
    }

    pub fn kill(&self, tab_id: &str) {
        let entry = {
            let mut map = self.inner.lock().unwrap();
            map.remove(tab_id)
        };
        if let Some(mut entry) = entry {
            let _ = entry.killer.kill();
        }
    }

    pub fn kill_all(&self) {
        let entries: Vec<PtyEntry> = {
            let mut map = self.inner.lock().unwrap();
            map.drain().map(|(_, v)| v).collect()
        };
        for mut entry in entries {
            let _ = entry.killer.kill();
        }
    }
}
