use clap::Parser;
use psxcdgen_ex::{file_writer::{ImageType, write_image}, config_reader};
use std::path::PathBuf;
use tool_helper::{Error, exit_with_error, read_file_to_string};

#[derive(Parser)]
#[clap(about = "Creates an ISO image from a description file", long_about = None)]
struct CommandLine {
    #[clap(value_enum, value_parser, help="Specifies the disc image type")]
    output_type: ImageType,

    #[clap(short='o', help="Output path; Some OUTPUT_TYPE might create additional files with different endings")]
    output_file: PathBuf,

    #[clap(long="list", id="Path to file", help="If set will list the CD content to stdout; With path will output list to file")]
    list_content: Option<Option<PathBuf>>,

    #[clap(value_parser, help="Input XML path for creating the image")]
    input_file: PathBuf,
}

fn run_main(cmd_line: CommandLine) -> Result<(), Error> {
    const PKG_MINIMUM_CONTENT_SIZE:usize = 512*1024;

    let (mut desc, lba_embedded_files) = psxcdgen_ex::process(config_reader::parse_xml(read_file_to_string(&cmd_line.input_file)?)?)?;
    let file_map                       = desc.create_file_map();

    psxcdgen_ex::process_files(file_map, lba_embedded_files)?;
    let content_size = desc.get_content_size();
    if content_size < PKG_MINIMUM_CONTENT_SIZE {
        let missing_size = PKG_MINIMUM_CONTENT_SIZE - content_size;
        desc.end_dummy_padding = missing_size;
        tool_helper::print_warning(format!("Content size {}b smaller then {}b.\nCD will be padded with {}b to work as a .pkg", content_size, PKG_MINIMUM_CONTENT_SIZE, missing_size));
    }
    
    if desc.lead_out_sectors == 0 {
        tool_helper::print_warning(format!("Consider adding a 2 second lead-out to your track (Add attribute 'lead-out=\"0:2:0\"' to your Track) for supporting the PS3"));
    }

    write_image(&desc, cmd_line.output_type, cmd_line.output_file)?;

    if let Some(list_content_option) = cmd_line.list_content {
        psxcdgen_ex::dump_content(&desc, tool_helper::open_output(&list_content_option)?)
    }
    
    else {
        Ok(())
    }
}

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