//! Live2DPlugin — Live2D 原生渲染插件
//!
//! 接管 Live2D 模式下的设备端渲染，替代 Firefox kiosk 方案。
//! 监听 ConfigReloaded 消息，当 render_type=Live2d 时启动原生渲染循环。

use crate::core::config::RenderType;
use crate::core::message::{Destination, Envelope, Message};
use crate::core::plugin::{Platform, Plugin, PluginContext, PluginInfo};
use anyhow::{Context, Result};
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread::JoinHandle;
use std::time::{Duration, Instant};

use super::renderer::{Live2DRenderer, Subtitle, SubtitleState};

pub struct Live2DPlugin {
    ctx: Option<PluginContext>,
    /// 渲染器句柄（运行在独立线程）
    renderer: Option<Arc<std::sync::Mutex<Live2DRenderer>>>,
    worker: Option<JoinHandle<()>>,
    /// 渲染停止信号
    stop_flag: Arc<AtomicBool>,
    /// 字幕共享状态（http 插件写入，渲染线程读取）
    subtitle: SubtitleState,
}

impl Live2DPlugin {
    pub fn new() -> Self {
        Self {
            ctx: None,
            renderer: None,
            worker: None,
            stop_flag: Arc::new(AtomicBool::new(false)),
            subtitle: Arc::new(Mutex::new(None)),
        }
    }
}

impl Default for Live2DPlugin {
    fn default() -> Self {
        Self::new()
    }
}

impl Plugin for Live2DPlugin {
    fn id(&self) -> &str {
        "live2d"
    }

    fn info(&self) -> PluginInfo {
        PluginInfo {
            name: "Live2D Renderer".to_string(),
            version: "0.1.0".to_string(),
            description: "Live2D 原生渲染（Cubism Core FFI + OpenGL ES 2.0）".to_string(),
            platform: Platform::Linux,
        }
    }

    fn dependencies(&self) -> Vec<String> {
        vec![]
    }

    fn init(&mut self, ctx: PluginContext) -> Result<()> {
        self.ctx = Some(ctx);
        Ok(())
    }

    fn start(&mut self) -> Result<()> {
        let ctx = self
            .ctx
            .as_ref()
            .context("live2d plugin context is not initialized")?;

        ctx.tx.send(Envelope {
            from: self.id().to_string(),
            to: Destination::Manager,
            message: Message::PluginReady(self.id().to_string()),
        })?;

        // 如果初始配置就是 Live2D 模式，立即启动渲染
        let config = (*ctx.config).clone();
        if config.character.render_type == RenderType::Live2d {
            println!("[Live2DPlugin] 检测到初始配置为 Live2D 模式，启动渲染");
            self.start_live2d(&config)?;
        }

        Ok(())
    }

    fn handle_message(&mut self, msg: Message) -> Result<()> {
        match msg {
            Message::ConfigReloaded(config) => {
                if config.character.render_type == RenderType::Live2d {
                    self.start_live2d(&config)?;
                } else {
                    self.stop_live2d();
                }
            }
            Message::Shutdown => {
                self.stop_live2d();
            }
            Message::Subtitle { text } => {
                // 设备端字幕：写入共享状态，渲染线程每帧读取，超时自动消失
                let ttl = Duration::from_millis(
                    (text.chars().count().max(1) as u64)
                        .saturating_mul(220)
                        .saturating_add(2500),
                );
                *self.subtitle.lock().unwrap() =
                    Some(Subtitle { text, expires_at: Instant::now() + ttl });
            }
            _ => {}
        }
        Ok(())
    }

    fn stop(&mut self) -> Result<()> {
        self.stop_live2d();
        Ok(())
    }
}

impl Live2DPlugin {
    fn start_live2d(&mut self, config: &crate::core::config::AppConfig) -> Result<()> {
        // 先停止旧的渲染
        self.stop_live2d();

        let model_rel = config
            .character
            .live2d_model
            .clone()
            .context("未配置 live2d_model")?;

        // Core .so 路径（相对项目根目录或绝对路径）
        let core_so = find_core_so()?;

        // live2d 资源根目录
        let live2d_base = find_live2d_base(config)?;

        let width = config.display.render_width as i32;
        let height = config.display.render_height as i32;

        let stop_flag = Arc::clone(&self.stop_flag);
        stop_flag.store(false, Ordering::SeqCst);

        let tx = self
            .ctx
            .as_ref()
            .context("no ctx")?
            .tx
            .clone();

        let renderer = Arc::new(std::sync::Mutex::new(
            Live2DRenderer::new(
                &core_so,
                &live2d_base,
                &model_rel,
                width,
                height,
                Arc::clone(&self.subtitle),
            )?,
        ));
        self.renderer = Some(Arc::clone(&renderer));

        // 渲染器初始化（含 texture 上传）已完成，释放主线程的 EGL 上下文绑定
        // 让渲染子线程能重新绑定（同一个 EGL context 不能同时在两个线程 current）
        {
            let r = renderer.lock().unwrap();
            r.gl_ctx.release_current();
        }

        let handle = std::thread::spawn(move || {
            // EGL 上下文是线程绑定的，需在渲染线程重新绑定
            {
                let r = renderer.lock().unwrap();
                if let Err(e) = r.gl_ctx.make_current() {
                    eprintln!("[Live2DPlugin] eglMakeCurrent 失败: {e}");
                    return;
                }
            }

            // 渲染循环
            loop {
                if stop_flag.load(Ordering::SeqCst) {
                    break;
                }
                // 检查 talking 状态（从 HTTP 插件共享的状态读取，这里通过轮询 config 实现）
                // 简化：直接渲染
                let render_result = {
                    let mut r = renderer.lock().unwrap();
                    r.render_frame()
                };
                if let Err(e) = render_result {
                    eprintln!("[Live2DPlugin] 渲染失败: {e}");
                    let _ = tx.send(Envelope {
                        from: "live2d".to_string(),
                        to: Destination::Manager,
                        message: Message::StateChanged {
                            old_state: "live2d_running".into(),
                            new_state: "live2d_error".into(),
                        },
                    });
                    break;
                }
                std::thread::sleep(std::time::Duration::from_millis(16));
            }
        });
        self.worker = Some(handle);

        println!("[Live2DPlugin] Live2D 原生渲染已启动: {model_rel}");
        Ok(())
    }

    fn stop_live2d(&mut self) {
        self.stop_flag.store(true, Ordering::SeqCst);
        if let Some(handle) = self.worker.take() {
            let _ = handle.join();
        }
        self.renderer = None;
    }
}

/// 查找 libLive2DCubismCore.so
fn find_core_so() -> Result<String> {
    // 候选路径优先级：
    // 1. 环境变量 SHOWEN_LIVE2D_CORE_SO
    // 2. 项目根 extern/libLive2DCubismCore.so（运行时随二进制一起部署）
    // 3. /usr/lib/libLive2DCubismCore.so
    // 4. /home/showen/Showen/ShowenV2/extern/libLive2DCubismCore.so
    if let Ok(p) = std::env::var("SHOWEN_LIVE2D_CORE_SO") {
        if std::path::Path::new(&p).exists() {
            return Ok(p);
        }
    }
    let candidates = [
        "extern/libLive2DCubismCore.so",
        "/usr/lib/libLive2DCubismCore.so",
        "/usr/local/lib/libLive2DCubismCore.so",
        "/home/showen/Showen/ShowenV2/extern/libLive2DCubismCore.so",
    ];
    for c in &candidates {
        if std::path::Path::new(c).exists() {
            return Ok(c.to_string());
        }
    }
    anyhow::bail!("找不到 libLive2DCubismCore.so，请设置环境变量 SHOWEN_LIVE2D_CORE_SO 或部署到 extern/")
}

/// 查找 live2d 资源根目录
fn find_live2d_base(config: &crate::core::config::AppConfig) -> Result<PathBuf> {
    let candidates = [
        PathBuf::from("configs/live2d"),
        PathBuf::from("/home/showen/Showen/ShowenV2/configs/live2d"),
        std::env::current_dir()?.join("configs/live2d"),
    ];
    for c in &candidates {
        if c.exists() {
            return Ok(c.clone());
        }
    }
    anyhow::bail!("找不到 configs/live2d 目录")
}
