mod cmd;
mod config;
mod pikpak;
mod theme;
mod tui;

use crate::config::{AppConfig, TuiConfig, UpdateCheck};
use crate::pikpak::PikPak;
use anyhow::{Result, anyhow};
use std::env;
use std::process::exit;
use std::sync::mpsc;

fn main() {
    if let Err(e) = entry() {
        eprintln!("Error: {e:#}");
        exit(1);
    }
}

fn entry() -> Result<()> {
    let args: Vec<String> = env::args().skip(1).collect();

    if args.is_empty() {
        return run_tui();
    }

    if args.len() >= 2 && cmd::wants_help(&args[1..]) && !matches!(args[0].as_str(), "--help" | "-h" | "help" | "--version" | "-V") {
        return cmd::print_command_help(&args[0]);
    }

    let update_rx = cli_update_check(&args);

    let result = match args[0].as_str() {
        "--version" | "-V" | "version" => {
            println!("pikpaktui {}", env!("CARGO_PKG_VERSION"));
            Ok(())
        }
        "--help" | "-h" | "help" => cmd::help::run(),
        "ls" => cmd::ls::run(&args[1..]),
        "mv" => cmd::mv::run(&args[1..]),
        "cp" => cmd::cp::run(&args[1..]),
        "rename" => cmd::rename::run(&args[1..]),
        "rm" => cmd::rm::run(&args[1..]),
        "mkdir" => cmd::mkdir::run(&args[1..]),
        "download" => cmd::download::run(&args[1..]),
        "upload" => cmd::upload::run(&args[1..]),
        "share" => cmd::share::run(&args[1..]),
        "quota" => cmd::quota::run(&args[1..]),
        "offline" => cmd::offline::run(&args[1..]),
        "tasks" => cmd::tasks::run(&args[1..]),
        "star" => cmd::star::run(&args[1..]),
        "unstar" => cmd::unstar::run(&args[1..]),
        "starred" => cmd::starred::run(&args[1..]),
        "events" => cmd::events::run(&args[1..]),
        "trash" => cmd::trash::run(&args[1..]),
        "untrash" => cmd::untrash::run(&args[1..]),
        "info" => cmd::info::run(&args[1..]),
        "link" => cmd::link::run(&args[1..]),
        "cat" => cmd::cat::run(&args[1..]),
        "play" => cmd::play::run(&args[1..]),
        "vip" => cmd::vip::run(),
        "login" => cmd::login::run(&args[1..]),
        "update" => cmd::update::run(),
        "completions" => cmd::completions::run(&args[1..]),
        "__complete_path" => cmd::complete_path::run(&args[1..]),
        other => Err(anyhow!(
            "unknown command: {other}\nRun `pikpaktui --help` for usage."
        )),
    };

    if let Some(rx) = update_rx {
        if let Ok(Some(version)) = rx.try_recv() {
            eprintln!(
                "\x1b[33m↑ Update available: v{} → v{} (run `pikpaktui update`)\x1b[0m",
                env!("CARGO_PKG_VERSION"),
                version
            );
        }
    }

    result
}

fn cli_update_check(args: &[String]) -> Option<mpsc::Receiver<Option<String>>> {
    let skip = matches!(
        args.first().map(|s| s.as_str()),
        Some("update" | "completions" | "__complete_path")
    );
    if skip {
        return None;
    }

    let config = TuiConfig::load();
    if config.update_check != UpdateCheck::Notify {
        return None;
    }

    let (tx, rx) = mpsc::channel();
    std::thread::spawn(move || {
        let _ = tx.send(cmd::update::check_for_update());
    });
    Some(rx)
}

fn run_tui() -> Result<()> {
    let mut client = PikPak::new()?;
    let tui_config = TuiConfig::load();
    client.thumbnail_size = tui_config.thumbnail_size.as_api_str().to_string();

    if client.has_valid_session() {
        return tui::run(client, tui_config);
    }

    let cfg = AppConfig::load()?;
    let credentials = match (cfg.username, cfg.password) {
        (Some(u), Some(p)) if !u.is_empty() && !p.is_empty() => Some((u, p)),
        _ => None,
    };

    tui::run_with_credentials(client, credentials, tui_config)
}
