use flutter_rust_bridge::frb;
use std::sync::Arc;

use crate::api::ffi_types::*;
use crate::sync_engine::SyncEngine;

/// 全局引擎实例
static ENGINE: once_cell::sync::OnceCell<Arc<SyncEngine>> = once_cell::sync::OnceCell::new();

/// 全局日志级别重载句柄（支持运行时热修改）
static LOG_RELOAD_HANDLE: once_cell::sync::OnceCell<
    tracing_subscriber::reload::Handle<tracing_subscriber::EnvFilter, tracing_subscriber::Registry>,
> = once_cell::sync::OnceCell::new();

// 内部类型 -> FFI 类型的转换函数

fn error_to_ffi(e: crate::errors::SyncError) -> SyncErrorFfi {
    match e {
        crate::errors::SyncError::Network(msg) => SyncErrorFfi::NetworkError { message: msg },
        crate::errors::SyncError::DiskFull { needed, available } => {
            SyncErrorFfi::DiskFull { needed, available }
        }
        crate::errors::SyncError::Auth(msg) => SyncErrorFfi::AuthError { message: msg },
        crate::errors::SyncError::Conflict { count } => SyncErrorFfi::ConflictError { count },
        crate::errors::SyncError::NotInitialized => SyncErrorFfi::NotInitialized,
        _ => SyncErrorFfi::InternalError {
            message: e.to_string(),
        },
    }
}

fn config_from_ffi(ffi: SyncConfigFfi) -> crate::models::SyncConfig {
    use crate::models::{ConflictStrategy, SyncMode, WcfDeleteMode};
    use std::path::PathBuf;

    let sync_mode = match ffi.sync_mode.as_str() {
        "upload_only" => SyncMode::UploadOnly,
        "download_only" => SyncMode::DownloadOnly,
        "album" => SyncMode::Album,
        "mirror_wcf" => SyncMode::MirrorWcf,
        _ => SyncMode::Full,
    };

    let conflict_strategy = match ffi.conflict_strategy.as_str() {
        "keep_local" => ConflictStrategy::KeepLocal,
        "keep_remote" => ConflictStrategy::KeepRemote,
        "newest_wins" => ConflictStrategy::NewestWins,
        "largest_wins" => ConflictStrategy::LargestWins,
        "manual" => ConflictStrategy::Manual,
        _ => ConflictStrategy::KeepBoth,
    };

    let wcf_delete_mode = match ffi.wcf_delete_mode.as_str() {
        "wcf_delete_sync_remote" => WcfDeleteMode::SyncRemote,
        _ => WcfDeleteMode::LocalOnly,
    };

    let bandwidth_limit = if ffi.bandwidth_limit_kbps > 0 {
        Some(ffi.bandwidth_limit_kbps * 1024)
    } else {
        None
    };

    crate::models::SyncConfig {
        base_url: ffi.base_url,
        access_token: ffi.access_token,
        refresh_token: ffi.refresh_token,
        local_root: PathBuf::from(&ffi.local_root),
        remote_root: ffi.remote_root,
        sync_mode,
        conflict_strategy,
        wcf_delete_mode,
        max_concurrent_transfers: ffi.max_concurrent_transfers as usize,
        bandwidth_limit,
        excluded_paths: ffi.excluded_paths,
        max_workers: ffi.max_workers as usize,
        data_dir: PathBuf::from(&ffi.data_dir),
        client_id: ffi.client_id,
    }
}

fn config_to_ffi(c: &crate::models::SyncConfig) -> SyncConfigFfi {
    use crate::models::{ConflictStrategy, SyncMode, WcfDeleteMode};

    let sync_mode = match c.sync_mode {
        SyncMode::Full => "full",
        SyncMode::UploadOnly => "upload_only",
        SyncMode::DownloadOnly => "download_only",
        SyncMode::Album => "album",
        SyncMode::MirrorWcf => "mirror_wcf",
    };

    let conflict_strategy = match c.conflict_strategy {
        ConflictStrategy::KeepLocal => "keep_local",
        ConflictStrategy::KeepRemote => "keep_remote",
        ConflictStrategy::KeepBoth => "keep_both",
        ConflictStrategy::NewestWins => "newest_wins",
        ConflictStrategy::LargestWins => "largest_wins",
        ConflictStrategy::Manual => "manual",
    };

    let wcf_delete_mode = match c.wcf_delete_mode {
        WcfDeleteMode::LocalOnly => "wcf_delete_local_only",
        WcfDeleteMode::SyncRemote => "wcf_delete_sync_remote",
    };

    SyncConfigFfi {
        base_url: c.base_url.clone(),
        access_token: c.access_token.clone(),
        refresh_token: c.refresh_token.clone(),
        local_root: c.local_root.to_string_lossy().to_string(),
        remote_root: c.remote_root.clone(),
        sync_mode: sync_mode.to_string(),
        conflict_strategy: conflict_strategy.to_string(),
        wcf_delete_mode: wcf_delete_mode.to_string(),
        max_concurrent_transfers: c.max_concurrent_transfers as u32,
        bandwidth_limit_kbps: c.bandwidth_limit.map(|b| b / 1024).unwrap_or(0),
        excluded_paths: c.excluded_paths.clone(),
        max_workers: c.max_workers as u32,
        data_dir: c.data_dir.to_string_lossy().to_string(),
        client_id: c.client_id.clone(),
        log_level: String::new(),
    }
}

fn status_to_ffi(s: crate::models::SyncStatusSnapshot) -> SyncStatusFfi {
    let error_msg = if let crate::models::SyncState::Error { ref message } = s.state {
        Some(message.clone())
    } else {
        s.error_message
    };

    let state = match s.state {
        crate::models::SyncState::Idle => "idle".to_string(),
        crate::models::SyncState::Initializing => "initializing".to_string(),
        crate::models::SyncState::InitialSync { .. } => "initialSync".to_string(),
        crate::models::SyncState::Continuous => "continuous".to_string(),
        crate::models::SyncState::Paused => "paused".to_string(),
        crate::models::SyncState::Error { .. } => "error".to_string(),
        crate::models::SyncState::Stopped => "stopped".to_string(),
    };

    SyncStatusFfi {
        state,
        synced_files: s.synced_files,
        total_files: s.total_files,
        uploading_count: s.uploading_count,
        downloading_count: s.downloading_count,
        conflict_count: s.conflict_count,
        error_count: s.error_count,
        last_sync_time: s.last_sync_time,
        error_message: error_msg,
    }
}

fn summary_to_ffi(s: crate::models::SyncSummary) -> SyncSummaryFfi {
    SyncSummaryFfi {
        uploaded: s.uploaded,
        downloaded: s.downloaded,
        renamed: s.renamed,
        moved: s.moved,
        conflicts: s.conflicts,
        failed: s.failed,
        skipped: s.skipped,
        deleted_local: s.deleted_local,
        deleted_remote: s.deleted_remote,
        duration_ms: s.duration_ms,
    }
}

fn album_result_to_ffi(r: crate::models::CloudAlbumCheckResult) -> CloudAlbumCheckResultFfi {
    CloudAlbumCheckResultFfi {
        dcim_exists: r.dcim_exists,
        pictures_exists: r.pictures_exists,
        dcim_uri: r.dcim_uri,
        pictures_uri: r.pictures_uri,
    }
}

/// 获取引擎引用，未初始化则返回错误
fn get_engine() -> Result<&'static SyncEngine, SyncErrorFfi> {
    ENGINE.get().map(|arc| arc.as_ref()).ok_or(SyncErrorFfi::NotInitialized)
}

/// 内部：应用日志级别到 reload handle
fn apply_log_level(level: &str) {
    if level.is_empty() {
        return;
    }
    if let Some(handle) = LOG_RELOAD_HANDLE.get() {
        let directive = format!("sync_core={}", level);
        match handle.modify(|filter| {
            *filter = tracing_subscriber::EnvFilter::new(&directive);
        }) {
            Ok(()) => eprintln!("[sync-core] 日志级别已切换为: {}", level),
            Err(e) => eprintln!("[sync-core] 修改日志级别失败: {}", e),
        }
    }
}

// ========== 生命周期 ==========

/// 初始化同步引擎
#[frb]
pub async fn init_sync_engine(config: SyncConfigFfi) -> Result<(), SyncErrorFfi> {
    eprintln!("[FFI] init_sync_engine ← mode={}, conflict={}, wcf_delete={}, concurrent={}, bandwidth={}kbps, log_level={}",
        config.sync_mode, config.conflict_strategy, config.wcf_delete_mode, config.max_concurrent_transfers,
        config.bandwidth_limit_kbps, config.log_level);

    // 确保本地同步目录存在
    let local_root = std::path::PathBuf::from(&config.local_root);
    if !local_root.exists() {
        std::fs::create_dir_all(&local_root).map_err(|e| SyncErrorFfi::InternalError {
            message: format!("无法创建同步目录: {}", e),
        })?;
    }

    // 确保程序数据目录存在
    let data_dir = std::path::PathBuf::from(&config.data_dir);
    let db_dir = data_dir.join("sync_core").join("datas");
    let log_dir = data_dir.join("sync_core").join("logs");
    if !db_dir.exists() {
        std::fs::create_dir_all(&db_dir).map_err(|e| SyncErrorFfi::InternalError {
            message: format!("无法创建数据库目录: {}", e),
        })?;
    }
    if !log_dir.exists() {
        std::fs::create_dir_all(&log_dir).map_err(|e| SyncErrorFfi::InternalError {
            message: format!("无法创建日志目录: {}", e),
        })?;
    }

    // 初始化 tracing 日志：输出到程序数据目录的 logs 和 stderr
    let log_path = log_dir.join("sync_log.txt");
    eprintln!("[sync-core] 日志文件: {}", log_path.display());

    let log_file = std::fs::OpenOptions::new()
        .create(true)
        .append(true)
        .open(&log_path)
        .ok();

    if log_file.is_none() {
        eprintln!("[sync-core] 警告: 无法创建日志文件 {}", log_path.display());
    }

    // 尝试初始化 subscriber（仅首次有效，后续调用忽略）
    {
        use tracing_subscriber::layer::SubscriberExt;
        use tracing_subscriber::util::SubscriberInitExt;

        let filter = tracing_subscriber::EnvFilter::from_default_env()
            .add_directive("sync_core=debug".parse().unwrap());

        let (reload_filter, reload_handle) =
            tracing_subscriber::reload::Layer::<_, tracing_subscriber::Registry>::new(filter);
        LOG_RELOAD_HANDLE.set(reload_handle).ok();

        let registry = tracing_subscriber::registry().with(reload_filter);

        if let Some(file) = log_file {
            let _ = registry
                .with(tracing_subscriber::fmt::layer()
                    .with_writer(std::sync::Mutex::new(file))
                    .with_ansi(false))
                .with(tracing_subscriber::fmt::layer()
                    .with_writer(std::io::stderr))
                .try_init();
        } else {
            let _ = registry
                .with(tracing_subscriber::fmt::layer()
                    .with_writer(std::io::stderr))
                .try_init();
        }
    }

    // 提取配置信息用于日志（在 move 之前）
    let log_sync_mode = config.sync_mode.clone();
    let log_conflict_strategy = config.conflict_strategy.clone();
    let log_max_concurrent = config.max_concurrent_transfers;
    let log_bandwidth = config.bandwidth_limit_kbps;
    let log_level = config.log_level.clone();

    let engine = SyncEngine::new(config_from_ffi(config)).await
        .map_err(error_to_ffi)?;

    ENGINE.set(Arc::new(engine))
        .map_err(|_| SyncErrorFfi::InternalError {
            message: "引擎已初始化".to_string(),
        })?;

    tracing::info!("同步引擎初始化完成, 日志文件: {}", log_path.display());
    tracing::info!(
        "配置: 模式={}, 冲突策略={}, 并发={}, 带宽限制={}kbps",
        log_sync_mode, log_conflict_strategy, log_max_concurrent, log_bandwidth,
    );
    if log_bandwidth > 0 {
        tracing::info!("仅对下载限速生效, 由于Cloudreve实现原因, 上传限速无法生效");
    }

    // 应用配置中的日志级别（热修改覆盖默认 debug）
    apply_log_level(&log_level);

    Ok(())
}

/// 销毁同步引擎
#[frb]
pub async fn dispose_sync_engine() -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] dispose_sync_engine ←");
    let engine = get_engine()?;
    engine.stop().await.map_err(error_to_ffi)?;

    #[cfg(feature = "windows-cfapi")]
    {
        engine.cleanup_wcf();
    }

    tracing::info!("同步引擎已停止");
    Ok(())
}

/// 进程退出前同步清理（WCF 模式下必须调用，确保占位符释放）
/// 此函数是同步的，不依赖 tokio runtime，可安全在 exit(0) 前调用
#[frb]
pub fn sync_shutdown() -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] sync_shutdown ←");
    #[cfg(feature = "windows-cfapi")]
    {
        let engine = match ENGINE.get() {
            Some(e) => e,
            None => return Ok(()),
        };
        engine.cleanup_wcf();
    }
    tracing::info!("同步引擎已同步清理");
    Ok(())
}

// ========== 同步控制 ==========

/// 执行初始全量同步
#[frb]
pub async fn start_initial_sync() -> Result<SyncSummaryFfi, SyncErrorFfi> {
    tracing::debug!("[FFI] start_initial_sync ←");
    let engine = get_engine()?;
    engine.ensure_token_fresh();
    engine.run_initial_sync().await
        .map(|s| {
            tracing::debug!("[FFI] start_initial_sync → uploaded={}, downloaded={}, conflicts={}, failed={}",
                s.uploaded, s.downloaded, s.conflicts, s.failed);
            summary_to_ffi(s)
        })
        .map_err(error_to_ffi)
}

/// 启动持续同步（后台运行，立即返回）
#[frb]
pub async fn start_continuous_sync() -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] start_continuous_sync ←");
    let engine = get_engine()?;
    let engine = engine.clone();
    tokio::spawn(async move {
        if let Err(e) = engine.run_continuous().await {
            tracing::error!("持续同步异常退出: {}", e);
        }
    });
    tracing::debug!("[FFI] start_continuous_sync → spawned");
    Ok(())
}

/// 停止同步
#[frb]
pub async fn stop_sync() -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] stop_sync ←");
    let engine = get_engine()?;
    engine.stop().await.map_err(error_to_ffi)
}

/// 暂停同步
#[frb]
pub async fn pause_sync() -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] pause_sync ←");
    let engine = get_engine()?;
    engine.pause().await.map_err(error_to_ffi)
}

/// 恢复同步
#[frb]
pub async fn resume_sync() -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] resume_sync ←");
    let engine = get_engine()?;
    engine.resume().await.map_err(error_to_ffi)
}

/// 强制同步（重新扫描全量差异）
#[frb]
pub async fn force_sync() -> Result<SyncSummaryFfi, SyncErrorFfi> {
    tracing::debug!("[FFI] force_sync ←");
    let engine = get_engine()?;
    engine.force_sync().await
        .map(|s| {
            tracing::debug!("[FFI] force_sync → uploaded={}, downloaded={}, conflicts={}, failed={}",
                s.uploaded, s.downloaded, s.conflicts, s.failed);
            summary_to_ffi(s)
        })
        .map_err(error_to_ffi)
}

/// 重置同步：停止任务 → 清空 DB → 清空本地目录 → 回到初始状态
#[frb]
pub async fn reset_sync() -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] reset_sync ←");
    let engine = get_engine()?;
    engine.reset_sync().await.map_err(error_to_ffi)
}

// ========== 状态查询 ==========

/// 获取同步状态快照
#[frb]
pub async fn get_sync_status() -> Result<SyncStatusFfi, SyncErrorFfi> {
    let engine = get_engine()?;
    let s = engine.status();
    tracing::trace!("[FFI] get_sync_status → state={:?}, synced={}, total={}", s.state, s.synced_files, s.total_files);
    Ok(status_to_ffi(s))
}

/// 获取活跃 Worker 数量
#[frb]
pub async fn get_active_worker_count() -> Result<u32, SyncErrorFfi> {
    let engine = get_engine()?;
    let count = engine.active_worker_count();
    tracing::trace!("[FFI] get_active_worker_count → {}", count);
    Ok(count)
}

/// 获取同步配置
#[frb]
pub async fn get_sync_config() -> Result<SyncConfigFfi, SyncErrorFfi> {
    let engine = get_engine()?;
    let c = engine.config().await;
    tracing::trace!("[FFI] get_sync_config → mode={:?}, conflict={:?}", c.sync_mode, c.conflict_strategy);
    Ok(config_to_ffi(&c))
}

/// 更新同步配置
#[frb]
pub async fn update_sync_config(config: SyncConfigFfi) -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] update_sync_config ← mode={}, conflict={}, wcf_delete={}, concurrent={}, bandwidth={}kbps",
        config.sync_mode, config.conflict_strategy, config.wcf_delete_mode, config.max_concurrent_transfers, config.bandwidth_limit_kbps);
    let engine = get_engine()?;
    engine.update_config(config_from_ffi(config)).await.map_err(error_to_ffi)
}

// ========== Token 管理 ==========

/// Dart 推送新 Token 给 Rust
#[frb]
pub async fn update_tokens(access_token: String) -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] update_tokens ← token_len={}", access_token.len());
    let engine = get_engine()?;
    engine.update_access_token(access_token).await;
    Ok(())
}

// ========== Windows 专用 ==========

/// 水合文件（Windows 按需下载）
#[frb]
pub async fn hydrate_file(local_path: String) -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] hydrate_file ← path={}", local_path);
    let engine = get_engine()?;
    engine.hydrate_file(&local_path).await.map_err(error_to_ffi)
}

// ========== Android 专用 ==========

/// 同步相册到云端
#[frb]
pub async fn sync_album_to_cloud(
    album_paths: Vec<String>,
    remote_dcim_uri: String,
) -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] sync_album_to_cloud ← paths={}, uri={}", album_paths.len(), remote_dcim_uri);
    let engine = get_engine()?;
    engine.sync_album(album_paths, &remote_dcim_uri).await.map_err(error_to_ffi)
}

/// 检查云端是否存在 DCIM/Pictures 目录
#[frb]
pub async fn check_cloud_album_dirs(base_uri: String) -> Result<CloudAlbumCheckResultFfi, SyncErrorFfi> {
    tracing::debug!("[FFI] check_cloud_album_dirs ← uri={}", base_uri);
    let engine = get_engine()?;
    engine.check_album_dirs(&base_uri).await
        .map(|r| {
            tracing::debug!("[FFI] check_cloud_album_dirs → dcim={}, pictures={}", r.dcim_exists, r.pictures_exists);
            album_result_to_ffi(r)
        })
        .map_err(error_to_ffi)
}

/// 在云端创建 DCIM/Pictures 目录
#[frb]
pub async fn create_cloud_album_dirs(base_uri: String) -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] create_cloud_album_dirs ← uri={}", base_uri);
    let engine = get_engine()?;
    engine.create_album_dirs(&base_uri).await.map_err(error_to_ffi)
}

// ========== 事件推送 ==========

/// 注册 Rust→Dart 事件推送通道
#[frb]
pub fn register_sync_event_sink(sink: crate::frb_generated::StreamSink<SyncEventFfi>) -> Result<(), SyncErrorFfi> {
    tracing::debug!("[FFI] register_sync_event_sink ←");
    let engine = get_engine()?;
    // 使用 tokio runtime 注册
    let rt = tokio::runtime::Handle::current();
    rt.block_on(engine.register_event_sink(sink));
    Ok(())
}

// ========== 日志级别 ==========

/// 运行时热修改日志级别（立即生效，无需重启）
#[frb]
pub fn set_sync_log_level(level: String) -> Result<(), SyncErrorFfi> {
    eprintln!("[FFI] set_sync_log_level ← level={}", level);
    let valid_levels = ["error", "warn", "info", "debug", "trace"];
    let level_lower = level.to_lowercase();
    if !valid_levels.contains(&level_lower.as_str()) {
        return Err(SyncErrorFfi::InternalError {
            message: format!("无效的日志级别: {}, 可选: {:?}", level, valid_levels),
        });
    }

    if LOG_RELOAD_HANDLE.get().is_none() {
        return Err(SyncErrorFfi::NotInitialized);
    }

    apply_log_level(&level_lower);
    Ok(())
}

// ========== 任务查询 ==========

/// 获取活跃的同步任务列表
#[frb]
pub async fn get_active_tasks() -> Result<Vec<SyncTaskFfi>, SyncErrorFfi> {
    let engine = get_engine()?;
    let tasks = engine.get_active_tasks().await.map_err(error_to_ffi)?;
    tracing::trace!("[FFI] get_active_tasks → count={}", tasks.len());
    Ok(tasks.into_iter().map(task_to_ffi).collect())
}

/// 获取最近同步任务列表
#[frb]
pub async fn get_recent_tasks(limit: u32) -> Result<Vec<SyncTaskFfi>, SyncErrorFfi> {
    tracing::trace!("[FFI] get_recent_tasks ← limit={}", limit);
    let engine = get_engine()?;
    let tasks = engine.get_recent_tasks(limit).await.map_err(error_to_ffi)?;
    tracing::trace!("[FFI] get_recent_tasks → count={}", tasks.len());
    Ok(tasks.into_iter().map(task_to_ffi).collect())
}

/// 获取任务详情（任务项列表）
#[frb]
pub async fn get_task_detail(task_id: String) -> Result<Vec<SyncTaskItemFfi>, SyncErrorFfi> {
    tracing::trace!("[FFI] get_task_detail ← task_id={}", task_id);
    let engine = get_engine()?;
    let items = engine.get_task_detail(&task_id).await.map_err(error_to_ffi)?;
    tracing::trace!("[FFI] get_task_detail → count={}", items.len());
    Ok(items.into_iter().map(task_item_to_ffi).collect())
}

/// 多维度查询任务项
#[frb]
pub async fn query_task_items(filter: TaskItemFilterFfi) -> Result<Vec<SyncTaskItemFfi>, SyncErrorFfi> {
    tracing::trace!("[FFI] query_task_items ← task_id={:?}, action={:?}, status={:?}, limit={}",
        filter.task_id, filter.action_type, filter.status, filter.limit);
    let engine = get_engine()?;
    let model_filter = crate::models::TaskItemFilter {
        task_id: filter.task_id,
        relative_path_contains: filter.relative_path_contains,
        action_type: filter.action_type,
        status: filter.status,
        limit: filter.limit.max(1).min(1000),
        offset: filter.offset,
    };
    let items = engine.query_task_items(&model_filter).await.map_err(error_to_ffi)?;
    tracing::trace!("[FFI] query_task_items → count={}", items.len());
    Ok(items.into_iter().map(task_item_to_ffi).collect())
}

fn task_to_ffi(t: crate::models::SyncTask) -> SyncTaskFfi {
    SyncTaskFfi {
        id: t.id,
        trigger: t.trigger.as_str().to_string(),
        total_count: t.total_count,
        completed_count: t.completed_count,
        failed_count: t.failed_count,
        status: t.status.as_str().to_string(),
        created_at: t.created_at,
        updated_at: t.updated_at,
        finished_at: t.finished_at,
    }
}

fn task_item_to_ffi(i: crate::models::SyncTaskItem) -> SyncTaskItemFfi {
    SyncTaskItemFfi {
        id: i.id,
        task_id: i.task_id,
        relative_path: i.relative_path,
        action_type: i.action_type.as_str().to_string(),
        status: i.status.as_str().to_string(),
        file_size: i.file_size,
        error_message: i.error_message,
        created_at: i.created_at,
        updated_at: i.updated_at,
    }
}
