#[allow(unused_imports)] // Some of the code is behind features and does need these imports.
use std::{
    backtrace::Backtrace,
    fs::File,
    io::{self, Write},
    panic::PanicInfo,
};

use crate::panic_message::print_debug_info;

mod dump_program;
mod panic_message;
mod system_info;
mod terminate_program;

pub struct PanicHandlingConfig {
    pub termination_method: String,
    pub termination_exit_code: Option<i32>,
    pub panic_info_log_file_destination: Option<String>,
    pub minidump_file_destination: Option<String>,
}

pub fn handle_error(
    panicinfo: &PanicInfo,
    panic_handling_config: PanicHandlingConfig,
    _captured_backtrace: Option<Backtrace>,
) {
    // Prints the panic information to stderr.
    print_debug_info("[PANIC HANDLER INFO] Writing panic info.");
    let log_panicinfo_status: Result<(), io::Error> = panic_message::log_message(panicinfo);
    print_debug_info(&format!(
        "[PANIC HANDLER INFO] Attempted to write panic info. Status: {log_panicinfo_status:?}."
    ));

    #[cfg(feature = "write_panic_log")]
    println!(
        "Panic log will be written to {:?}",
        panic_handling_config
            .panic_info_log_file_destination
            .clone()
            .unwrap()
    );
    #[cfg(feature = "write_minidump")]
    println!(
        "Minidump will be written to {:?}",
        panic_handling_config
            .minidump_file_destination
            .clone()
            .unwrap()
    );

    // Writes the panic log to the panic_handling_config specified path.
    #[cfg(feature = "write_panic_log")]
    {
        // Reads the system information.
        print_debug_info("[PANIC HANDLER INFO] Reading system info.");
        let system_info: String = system_info::get_info();
        print_debug_info("[PANIC HANDLER INFO] Read system info.");

        // Actually writes the panic log file.
        print_debug_info(&format!(
            "[PANIC HANDLER INFO] Writing information to panic log file \"{}\".",
            panic_handling_config
                .panic_info_log_file_destination
                .clone()
                .unwrap()
        ));
        let panic_log_file: Result<File, io::Error> = File::create(
            panic_handling_config
                .panic_info_log_file_destination
                .clone()
                .unwrap(),
        );
        let _write_file_status: Result<(), io::Error> = match panic_log_file {
            Ok(mut file) => file.write_all(
                panic_message::get_panic_log_file_message(
                    panicinfo,
                    &system_info,
                    _captured_backtrace,
                )
                .as_bytes(),
            ),
            Err(err) => Err(err),
        };
        print_debug_info(
            &format!("[PANIC HANDLER INFO] Attempted to write panic log file. Status: {_write_file_status:?}."),
        );
    }

    // Writes a minidump of the current process.
    #[cfg(feature = "write_minidump")]
    {
        print_debug_info(&format!(
            "[PANIC HANDLER INFO] Writing minidump file to \"{}\".",
            panic_handling_config
                .minidump_file_destination
                .clone()
                .unwrap()
        ));
        let _minidump_write_status = dump_program::write_minidump(
            panic_handling_config
                .minidump_file_destination
                .unwrap()
                .to_string(),
            panic_handling_config.termination_exit_code,
        );
        print_debug_info(
            &format!("[PANIC HANDLER INFO] Attempted to write minidump file. Status: {_minidump_write_status:?}."),
        );
    }

    // Terminates the program by the panic_handling_config specified method (and exit code if method is "exit").
    terminate_program::terminate_by_specified_method(
        &panic_handling_config.termination_method,
        panic_handling_config.termination_exit_code,
    );
}
