use clap::{Parser, Subcommand};
use psxfileconv::{audio::{self, *}, images::*, nothing};
use std::path::PathBuf;
use tool_helper::{exit_with_error, Error};

#[derive(Parser)]
#[clap(about = "Converts files to various JabyEngine related file formats", long_about = None)]
struct CommandLine {
    #[clap(long="lz4", default_value_t=false)]
    compress_lz4: bool,

    #[clap(short='o')]
    output_file: Option<PathBuf>,

    #[clap(value_parser)]
    input_file: Option<PathBuf>,

    #[clap(subcommand)]
    sub_command: SubCommands,
}

#[derive(Subcommand)]
enum SubCommands {
    Nothing,
    SimpleTIM(reduced_tim::Arguments),
    TIM(tim::Arguments),
    VAG(vag::Arguments),
    XA(xa::Arguments),
}

fn run_main(cmd: CommandLine) -> Result<(), Error> {
    let mut input       = tool_helper::open_input(&cmd.input_file)?;
    let mut buffer      = Vec::<u8>::new();
    let mut output_file = tool_helper::open_output(&cmd.output_file)?;
    let     dst_buffer  = {
        if cmd.compress_lz4 {
            &mut buffer as &mut dyn std::io::Write
        }

        else {
            &mut output_file as &mut dyn std::io::Write
        }
    };

    let cmd_result: Result<(), Error> = {
        match cmd.sub_command {
            SubCommands::Nothing         => nothing::copy(&mut input, dst_buffer),
            SubCommands::SimpleTIM(args) => reduced_tim::convert(args, input, dst_buffer),
            SubCommands::TIM(args)       => tim::convert(args, input, dst_buffer),
            SubCommands::VAG(args)       => audio::vag::convert(args, &cmd.output_file, input, dst_buffer),
            SubCommands::XA(args)        => audio::xa::convert(args, input, dst_buffer),
        }
    };
    
    if let Err(cmd_error) = cmd_result {
        if let Some(file_path) = cmd.output_file {
            let _result = std::fs::remove_file(file_path);
        }

        else {
            tool_helper::print_warning("Open stream detected! Incomplete file can not be deleted".to_owned());
        }

        return Err(cmd_error);
    }

    // We encoded the file to a temporary buffer and now need to write it
    if cmd.compress_lz4 {
        let buffer = tool_helper::compress::psx_default::lz4(&buffer)?;
        output_file.write(&buffer)?;
    }

    Ok(()) 
}

fn main() {
    match CommandLine::try_parse() {
        Ok(cmd)    => {
            if let Err(error) = run_main(cmd) {
                exit_with_error(error);
            }
        },
        Err(error) => println!("{}", error)
    }
}