use dioxus::prelude::*;
use dioxus_desktop::{use_window, LogicalSize};
use std::env;
use std::fs::{File, OpenOptions, create_dir_all};
use std::io::{BufRead, BufReader, Write};
use std::path::Path;
use std::process::{Command as ProcCommand, Child, Stdio};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use notify_rust::Notification;
use serde::{Deserialize, Serialize};
use serde_json::Value;

// App state
#[derive(Debug, Clone)]
struct AppState {
    name: String,
    access_key: String,
    secret_key: String,
    status_text: String,
    sync_processes: Arc<Mutex<Vec<Child>>>,
    sync_active: Arc<Mutex<bool>>,
    sync_statuses: Arc<Mutex<Vec<SyncStatus>>>,
    show_config_dialog: bool,
    show_about_dialog: bool,
    current_screen: Screen,
}

#[derive(Debug, Clone)]
enum Screen {
    Main,
    Status,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct RcloneConfig {
    name: String,
    remote_path: String,
    local_path: String,
    access_key: String,
    secret_key: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct SyncStatus {
    name: String,
    status: String,
    transferred: String,
    bytes: String,
    errors: usize,
    last_updated: String,
}

#[derive(Debug, Clone)]
enum Message {
    NameChanged(String),
    AccessKeyChanged(String),
    SecretKeyChanged(String),
    SaveConfig,
    StartSync,
    StopSync,
    UpdateStatus(Vec<SyncStatus>),
    ShowConfigDialog(bool),
    ShowAboutDialog(bool),
    ShowStatusScreen,
    BackToMain,
    None,
}

fn main() {
    dioxus_desktop::launch(app);
}

fn app(cx: Scope) -> Element {
    let window = use_window();
    window.set_inner_size(LogicalSize::new(800, 600));

    let state = use_ref(cx, || AppState {
        name: String::new(),
        access_key: String::new(),
        secret_key: String::new(),
        status_text: "Enter credentials to set up sync".to_string(),
        sync_processes: Arc::new(Mutex::new(Vec::new())),
        sync_active: Arc::new(Mutex::new(false)),
        sync_statuses: Arc::new(Mutex::new(Vec::new())),
        show_config_dialog: false,
        show_about_dialog: false,
        current_screen: Screen::Main,
    });

    // Monitor sync status
    use_future( async move {
        let state = state.clone();
        async move {
            let mut last_check = Instant::now();
            let check_interval = Duration::from_secs(5);

            loop {
                tokio::time::sleep(Duration::from_secs(1)).await;

                if !*state.read().sync_active.lock().unwrap() {
                    continue;
                }

                if last_check.elapsed() < check_interval {
                    continue;
                }

                last_check = Instant::now();

                match read_rclone_configs() {
                    Ok(configs) => {
                        let mut new_statuses = Vec::new();
                        for config in configs {
                            match get_rclone_status(&config.name) {
                                Ok(status) => new_statuses.push(status),
                                Err(e) => eprintln!("Failed to get status: {}", e),
                            }
                        }
                        *state.write().sync_statuses.lock().unwrap() = new_statuses.clone();
                        state.write().status_text = format!("Syncing {} repositories...", new_statuses.len());
                    }
                    Err(e) => eprintln!("Failed to read configs: {}", e),
                }
            }
        }
    });

    cx.render(rsx! {
        div {
            class: "app",
            // Main menu bar
            div {
                class: "menu-bar",
                button {
                    onclick: move |_| state.write().show_config_dialog = true,
                    "Add Sync Configuration"
                }
                button {
                    onclick: move |_| state.write().show_about_dialog = true,
                    "About"
                }
            }

            // Main content
            {match state.read().current_screen {
                Screen::Main => rsx! {
                    div {
                        class: "main-screen",
                        h1 { "General Bots" }
                        p { "{state.read().status_text}" }
                        button {
                            onclick: move |_| start_sync(&state),
                            "Start Sync"
                        }
                        button {
                            onclick: move |_| stop_sync(&state),
                            "Stop Sync"
                        }
                        button {
                            onclick: move |_| state.write().current_screen = Screen::Status,
                            "Show Status"
                        }
                    }
                },
                Screen::Status => rsx! {
                    div {
                        class: "status-screen",
                        h1 { "Sync Status" }
                        div {
                            class: "status-list",
                            for status in state.read().sync_statuses.lock().unwrap().iter() {
                                div {
                                    class: "status-item",
                                    h2 { "{status.name}" }
                                    p { "Status: {status.status}" }
                                    p { "Transferred: {status.transferred}" }
                                    p { "Bytes: {status.bytes}" }
                                    p { "Errors: {status.errors}" }
                                    p { "Last Updated: {status.last_updated}" }
                                }
                            }
                        }
                        button {
                            onclick: move |_| state.write().current_screen = Screen::Main,
                            "Back"
                        }
                    }
                }
            }}

            // Config dialog
            if state.read().show_config_dialog {
                div {
                    class: "dialog",
                    h2 { "Add Sync Configuration" }
                    input {
                        value: "{state.read().name}",
                        oninput: move |e| state.write().name = e.value.clone(),
                        placeholder: "Enter sync name",
                    }
                    input {
                        value: "{state.read().access_key}",
                        oninput: move |e| state.write().access_key = e.value.clone(),
                        placeholder: "Enter access key",
                    }
                    input {
                        value: "{state.read().secret_key}",
                        oninput: move |e| state.write().secret_key = e.value.clone(),
                        placeholder: "Enter secret key",
                    }
                    button {
                        onclick: move |_| {
                            save_config(&state);
                            state.write().show_config_dialog = false;
                        },
                        "Save"
                    }
                    button {
                        onclick: move |_| state.write().show_config_dialog = false,
                        "Cancel"
                    }
                }
            }

            // About dialog
            if state.read().show_about_dialog {
                div {
                    class: "dialog",
                    h2 { "About General Bots" }
                    p { "Version: 1.0.0" }
                    p { "A professional-grade sync tool for OneDrive/Dropbox-like functionality." }
                    button {
                        onclick: move |_| state.write().show_about_dialog = false,
                        "Close"
                    }
                }
            }
        }
    })
}

// Save sync configuration
fn save_config(state: &UseRef<AppState>) {
    if state.read().name.is_empty() || state.read().access_key.is_empty() || state.read().secret_key.is_empty() {
        state.write_with(|state| state.status_text = "All fields are required!".to_string());
        return;
    }

    let new_config = RcloneConfig {
        name: state.read().name.clone(),
        remote_path: format!("s3://{}", state.read().name),
        local_path: Path::new(&env::var("HOME").unwrap()).join("General Bots").join(&state.read().name).to_string_lossy().to_string(),
        access_key: state.read().access_key.clone(),
        secret_key: state.read().secret_key.clone(),
    };

    if let Err(e) = save_rclone_config(&new_config) {
        state.write_with(|state| state.status_text = format!("Failed to save config: {}", e));
    } else {
        state.write_with(|state| state.status_text = "New sync saved!".to_string());
    }
}

// Start sync process
fn start_sync(state: &UseRef<AppState>) {
    let mut processes = state.write_with(|state| state.sync_processes.lock().unwrap());
    processes.clear();

    match read_rclone_configs() {
        Ok(configs) => {
            for config in configs {
                match run_sync(&config) {
                    Ok(child) => processes.push(child),
                    Err(e) => eprintln!("Failed to start sync: {}", e),
                }
            }
            state.write_with(|state| *state.sync_active.lock().unwrap() = true);
            state.write_with(|state| state.status_text = format!("Syncing with {} configurations.", processes.len()));
        }
        Err(e) => state.write_with(|state| state.status_text = format!("Failed to read configurations: {}", e)),
    }
}

// Stop sync process
fn stop_sync(state: &UseRef<AppState>) {
    let mut processes = state.write_with(|state| state.sync_processes.lock().unwrap());
    for child in processes.iter_mut() {
        let _ = child.kill();
    }
    processes.clear();
    state.write_with(|state| *state.sync_active.lock().unwrap() = false);
    state.write_with(|state| state.status_text = "Sync stopped.".to_string());
}

// Utility functions (rclone, notifications, etc.)
fn save_rclone_config(config: &RcloneConfig) -> Result<(), String> {
    let home_dir = env::var("HOME").map_err(|_| "HOME environment variable not set".to_string())?;
    let config_path = Path::new(&home_dir).join(".config/rclone/rclone.conf");

    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(&config_path)
        .map_err(|e| format!("Failed to open config file: {}", e))?;

    writeln!(file, "[{}]", config.name)
        .and_then(|_| writeln!(file, "type = s3"))
        .and_then(|_| writeln!(file, "provider = Other"))
        .and_then(|_| writeln!(file, "access_key_id = {}", config.access_key))
        .and_then(|_| writeln!(file, "secret_access_key = {}", config.secret_key))
        .and_then(|_| writeln!(file, "endpoint = https://drive-api.pragmatismo.com.br"))
        .and_then(|_| writeln!(file, "acl = private"))
        .map_err(|e| format!("Failed to write config: {}", e))
}

fn read_rclone_configs() -> Result<Vec<RcloneConfig>, String> {
    let home_dir = env::var("HOME").map_err(|_| "HOME environment variable not set".to_string())?;
    let config_path = Path::new(&home_dir).join(".config/rclone/rclone.conf");

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

    let file = File::open(&config_path).map_err(|e| format!("Failed to open config file: {}", e))?;
    let reader = BufReader::new(file);
    let mut configs = Vec::new();
    let mut current_config: Option<RcloneConfig> = None;

    for line in reader.lines() {
        let line = line.map_err(|e| format!("Failed to read line: {}", e))?;
        if line.is_empty() || line.starts_with('#') {
            continue;
        }

        if line.starts_with('[') && line.ends_with(']') {
            if let Some(config) = current_config.take() {
                configs.push(config);
            }
            let name = line[1..line.len()-1].to_string();
            current_config = Some(RcloneConfig {
                name: name.clone(),
                remote_path: format!("s3://{}", name),
                local_path: Path::new(&home_dir).join("General Bots").join(&name).to_string_lossy().to_string(),
                access_key: String::new(),
                secret_key: String::new(),
            });
        } else if let Some(ref mut config) = current_config {
            if let Some(pos) = line.find('=') {
                let key = line[..pos].trim().to_string();
                let value = line[pos+1..].trim().to_string();
                match key.as_str() {
                    "access_key_id" => config.access_key = value,
                    "secret_access_key" => config.secret_key = value,
                    _ => {}
                }
            }
        }
    }

    if let Some(config) = current_config {
        configs.push(config);
    }

    Ok(configs)
}

fn run_sync(config: &RcloneConfig) -> Result<Child, std::io::Error> {
    let local_path = Path::new(&config.local_path);
    if !local_path.exists() {
        create_dir_all(local_path)?;
    }

    ProcCommand::new("rclone")
        .arg("sync")
        .arg(&config.remote_path)
        .arg(&config.local_path)
        .arg("--no-check-certificate")
        .arg("--verbose")
        .arg("--rc")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()
}

fn get_rclone_status(remote_name: &str) -> Result<SyncStatus, String> {
    let output = ProcCommand::new("rclone")
        .arg("rc")
        .arg("core/stats")
        .arg("--json")
        .output()
        .map_err(|e| format!("Failed to execute rclone rc: {}", e))?;

    if !output.status.success() {
        return Err(format!("rclone rc failed: {}", String::from_utf8_lossy(&output.stderr)));
    }

    let json = String::from_utf8_lossy(&output.stdout);
    let parsed: Result<Value, _> = serde_json::from_str(&json);
    match parsed {
        Ok(value) => {
            let transferred = value.get("bytes").and_then(|v| v.as_u64()).unwrap_or(0);
            let errors = value.get("errors").and_then(|v| v.as_u64()).unwrap_or(0);
            let speed = value.get("speed").and_then(|v| v.as_f64()).unwrap_or(0.0);

            let status = if errors > 0 {
                "Error occurred".to_string()
            } else if speed > 0.0 {
                "Transferring".to_string()
            } else if transferred > 0 {
                "Completed".to_string()
            } else {
                "Initializing".to_string()
            };

            Ok(SyncStatus {
                name: remote_name.to_string(),
                status,
                transferred: format_bytes(transferred),
                bytes: format!("{}/s", format_bytes(speed as u64)),
                errors: errors as usize,
                last_updated: chrono::Local::now().format("%H:%M:%S").to_string(),
            })
        }
        Err(e) => Err(format!("Failed to parse rclone status: {}", e)),
    }
}

fn format_bytes(bytes: u64) -> String {
    const KB: u64 = 1024;
    const MB: u64 = KB * 1024;
    const GB: u64 = MB * 1024;

    if bytes >= GB {
        format!("{:.2} GB", bytes as f64 / GB as f64)
    } else if bytes >= MB {
        format!("{:.2} MB", bytes as f64 / MB as f64)
    } else if bytes >= KB {
        format!("{:.2} KB", bytes as f64 / KB as f64)
    } else {
        format!("{} B", bytes)
    }
}