#![feature(io_error_more)]
use std::{
    fs, io,
    path::{Path, PathBuf},
    process::ExitCode,
};

use clap::Parser;

#[derive(Debug, Parser)]
struct Args {
    #[clap(short, long)]
    verbose: bool,
    #[clap(short, long)]
    no_copy: bool,
    src: PathBuf,
    dst: PathBuf,
}

fn run(args: &Args) -> Result<(), io::Error> {
    let src: &Path = args.src.as_ref();
    let dst: &Path = args.dst.as_ref();

    if args.verbose {
        eprintln!("mv: rename {} -> {}", src.display(), dst.display());
    }

    match fs::rename(src, dst) {
        Ok(()) => return Ok(()),
        Err(e) if e.kind() == io::ErrorKind::CrossesDevices => {
            if args.no_copy {
                if args.verbose {
                    eprintln!("mv: --no-copy is specified and a move is a cross-device operation");
                }
                return Err(e);
            }
        }
        Err(e) => return Err(e),
    }

    if src.is_file() {
        let filename = src.file_name().unwrap();

        let dst = if dst.is_dir() {
            dst.join(filename)
        } else {
            dst.into()
        };

        if args.verbose {
            eprintln!("mv: copy {} -> {}", src.display(), dst.display());
        }
        fs::copy(src, dst)?;

        if args.verbose {
            eprintln!("mv: rm {}", src.display());
        }
        fs::remove_file(src)?;
    } else {
        // TODO mv symlink, mv dir
        todo!()
    }

    Ok(())
}

fn main() -> ExitCode {
    let args = Args::parse();

    match run(&args) {
        Ok(()) => ExitCode::SUCCESS,
        Err(error) => {
            eprintln!("{}: {error}", args.src.display());
            ExitCode::FAILURE
        }
    }
}
