mod engine;
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use tauri::Manager;

use engine::{
  aria2_add_torrent, aria2_add_uri, aria2_change_global_option, aria2_get_task_detail,
  aria2_list_tasks, aria2_pause_all, aria2_pause_task, aria2_remove_task,
  aria2_remove_task_record, aria2_resume_all, aria2_resume_task, detect_aria2_binary,
  engine_start, engine_status, engine_stop,
  load_torrent_file,
  open_path_in_file_manager, stop_engine_for_exit, EngineState,
};

#[tauri::command]
async fn focus_main_window(app: tauri::AppHandle) -> Result<(), String> {
  let window = app
    .get_webview_window("main")
    .ok_or_else(|| "메인 창을 찾을 수 없습니다.".to_string())?;

  window
    .show()
    .map_err(|error| format!("창 표시 실패: {error}"))?;
  window
    .unminimize()
    .map_err(|error| format!("창 복원 실패: {error}"))?;
  window
    .set_focus()
    .map_err(|error| format!("창 포커스 실패: {error}"))?;
  Ok(())
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ExternalAddRequest {
  url: String,
  out: Option<String>,
  dir: Option<String>,
  referer: Option<String>,
  user_agent: Option<String>,
  authorization: Option<String>,
  cookie: Option<String>,
  proxy: Option<String>,
  split: Option<u32>,
}

fn external_add_queue_path() -> Result<PathBuf, String> {
  let home = std::env::var("HOME").map_err(|err| format!("HOME 경로 확인 실패: {err}"))?;
  Ok(PathBuf::from(home).join(".gdown").join("external_add_queue.jsonl"))
}

#[tauri::command]
fn take_external_add_requests() -> Result<Vec<ExternalAddRequest>, String> {
  let path = external_add_queue_path()?;
  let parent = path
    .parent()
    .ok_or_else(|| "큐 디렉터리 경로를 계산할 수 없습니다.".to_string())?;
  fs::create_dir_all(parent).map_err(|err| format!("큐 디렉터리 생성 실패: {err}"))?;

  if !path.exists() {
    return Ok(Vec::new());
  }

  let content = fs::read_to_string(&path).map_err(|err| format!("큐 읽기 실패: {err}"))?;
  let mut requests: Vec<ExternalAddRequest> = Vec::new();
  for line in content.lines() {
    let trimmed = line.trim();
    if trimmed.is_empty() {
      continue;
    }
    if let Ok(item) = serde_json::from_str::<ExternalAddRequest>(trimmed) {
      requests.push(item);
    }
  }

  let mut file = fs::OpenOptions::new()
    .write(true)
    .truncate(true)
    .open(&path)
    .map_err(|err| format!("큐 초기화 실패: {err}"))?;
  file
    .write_all(b"")
    .map_err(|err| format!("큐 파일 쓰기 실패: {err}"))?;

  Ok(requests)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
  tauri::Builder::default()
    .manage(EngineState::default())
    .plugin(tauri_plugin_dialog::init())
    .plugin(tauri_plugin_deep_link::init())
    .on_window_event(|window, event| {
      if let tauri::WindowEvent::CloseRequested { .. } = event {
        if window.label() == "main" {
          let state = window.state::<EngineState>();
          stop_engine_for_exit(&state);
        }
      }
    })
    .setup(|app| {
      if cfg!(debug_assertions) {
        app.handle().plugin(
          tauri_plugin_log::Builder::default()
            .level(log::LevelFilter::Info)
            .build(),
        )?;
      }
      Ok(())
    })
    .invoke_handler(tauri::generate_handler![
      engine_start,
      engine_stop,
      engine_status,
      detect_aria2_binary,
      aria2_add_torrent,
      aria2_add_uri,
      aria2_change_global_option,
      aria2_get_task_detail,
      aria2_list_tasks,
      aria2_pause_task,
      aria2_resume_task,
      aria2_remove_task,
      aria2_remove_task_record,
      aria2_pause_all,
      aria2_resume_all,
      load_torrent_file,
      open_path_in_file_manager,
      focus_main_window,
      take_external_add_requests
    ])
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}
