// src-tauri/src/commands/calibration.rs
use crate::commands::serial::SerialConnectionState;
use crate::serial_core::calibration_session::{CalibrationProgress, CalibrationSession};
use crate::serial_core::codecs::tactile_a::TactileACsvExporter;
use crate::serial_core::error::SerialError;
use crate::serial_core::record::{write_csv, CsvExporter};
use crate::serial_core::serial::{run_serial_with_calibration, PollMode, TactileAPollRequester};
use log::info;
use serde::Serialize;
use std::fs::File;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use tauri::{async_runtime::JoinHandle, AppHandle, Manager, State};
use tokio_serial::SerialPortBuilderExt;
use tokio_util::sync::CancellationToken;

const DEFAULT_TACTILE_COLS: usize = 7;
const DEFAULT_TACTILE_ROWS: usize = 12;
const DEFAULT_TACTILE_POLL_INTERVAL_MS: u64 = 10;
const DEFAULT_TACTILE_REPLY_TIMEOUT_MS: u64 = 140;

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CalibrationResponse {
    pub success: bool,
    pub message: String,
    pub progress: Option<CalibrationProgress>,
}

struct CalibrationSessionData {
    cancel: CancellationToken,
    task: JoinHandle<()>,
}

#[tauri::command]
pub async fn serial_calibrate_with_coarse(
    app: AppHandle,
    port: String,
    target_frames: usize,
    max_rounds: usize,
    state: State<'_, SerialConnectionState>,
) -> Result<CalibrationResponse, SerialError> {
    let port_name = port.trim().to_string();
    if port_name.is_empty() {
        return Err(SerialError::InvalidConfig);
    }

    // 检查是否有活跃的标定会话
    {
        let calibration_session = state
            .calibration_session
            .lock()
            .map_err(|_| SerialError::StateError)?;
        if calibration_session.is_some() {
            return Err(SerialError::AlreadyConnected);
        }
    }

    // 创建新的标定会话
    let mut session = CalibrationSession::new(target_frames, max_rounds);
    session.start();

    let cancel = CancellationToken::new();
    let session_started_at = Instant::now();

    let task_cancel = cancel.clone();
    let task_app = app.clone();
    // let task_port_name = port_name.clone();
    let progress = session.get_progress();
    let session_for_state = session.clone();
    let port = tokio_serial::new(&port_name, 921600)
        .open_native_async()
        .map_err(|_| SerialError::OpenError)?;

    let _ = tauri::async_runtime::spawn(async move {
        // 这里调用新的标定处理函数
        if let Err(error) = run_serial_with_calibration(
            task_app.clone(),
            port,
            session_started_at,
            task_cancel,
            session,
        )
        .await
        {
            eprintln!("标定任务异常退出: {error}");
        }
    });

    // 保存标定会话状态
    let mut calibration_session = state
        .calibration_session
        .lock()
        .map_err(|_| SerialError::StateError)?;
    *calibration_session = Some(session_for_state);

    Ok(CalibrationResponse {
        success: true,
        message: "标定已开始".to_string(),
        progress: Some(progress),
    })
}

#[tauri::command]
pub async fn serial_calibrate_add_weight(
    state: State<'_, SerialConnectionState>,
) -> Result<CalibrationResponse, SerialError> {
    let mut calibration_session = state
        .calibration_session
        .lock()
        .map_err(|_| SerialError::StateError)?;

    if let Some(session) = calibration_session.as_mut() {
        match session.weight_added() {
            Ok(_) => Ok(CalibrationResponse {
                success: true,
                message: "配重已添加，继续标定".to_string(),
                progress: Some(session.get_progress()),
            }),
            Err(e) => Err(SerialError::StateError),
        }
    } else {
        Err(SerialError::StateError)
    }
}

#[tauri::command]
pub fn serial_calibrate_status(
    state: State<'_, SerialConnectionState>,
) -> Result<CalibrationResponse, SerialError> {
    let calibration_session = state
        .calibration_session
        .lock()
        .map_err(|_| SerialError::StateError)?;

    if let Some(session) = calibration_session.as_ref() {
        Ok(CalibrationResponse {
            success: true,
            message: "标定状态".to_string(),
            progress: Some(session.get_progress()),
        })
    } else {
        Ok(CalibrationResponse {
            success: false,
            message: "没有活跃的标定会话".to_string(),
            progress: None,
        })
    }
}
