#![allow(incomplete_features)]
#![feature(const_generics)]
#![feature(maybe_uninit_extra)]
#![feature(const_in_array_repeat_expressions)]



mod common;
mod entity;
mod patch;
mod login;
mod ship;

use std::thread;
use std::time::SystemTime;
use log::{info};

use patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd};
use login::login::LoginServerState;
use login::character::CharacterServerState;
use ship::ship::ShipServerState;
use entity::account::{UserAccount, UserSettings};
use entity::gateway::{EntityGateway, InMemoryGateway};
use entity::item::ItemLocation;
use libpso::{utf8_to_array, utf8_to_utf16_array};
//use crate::utf8_to_utf16_array;

use libpso::item::*;

fn setup_logger() {
    let colors = fern::colors::ColoredLevelConfig::new()
        .error(fern::colors::Color::Red)
        .warn(fern::colors::Color::Yellow)
        .info(fern::colors::Color::Green)
        .debug(fern::colors::Color::White)
        .trace(fern::colors::Color::BrightBlack);
    let stdio = fern::Dispatch::new()
        .level(log::LevelFilter::Debug)
        .format(move |out, message, record| {
            out.finish(format_args!(
                "\x1B[{}m[{}][{}][{}] {}\x1B[0m",
                colors.get_color(&record.level()).to_fg_str(),
                chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                record.target(),
                record.level(),
                message,
            ))
        })
        .chain(std::io::stdout());
    let fileout = fern::Dispatch::new()
        .level(log::LevelFilter::Trace)
        .chain(fern::log_file(format!("elseware-{}.log", chrono::Local::now().format("%Y-%m-%d_%H:%M:%S"))).unwrap());
    fern::Dispatch::new()
        .chain(stdio)
        .chain(fileout)
        .apply().unwrap();
}


fn main() {
    setup_logger();
    let mut entity_gateway = InMemoryGateway::new();

    let fake_user = UserAccount {
        id: 1,
        username: "hi".to_string(),
        password: bcrypt::hash("qwer", 5).unwrap(),
        guildcard: Some(1),
        team_id: None,
        banned: false,
        muted_until: SystemTime::now(),
        created_at: SystemTime::now(),
        flags: 0,
    };
    entity_gateway.set_user(&fake_user);
    entity_gateway.create_user_settings_by_user(&fake_user);
    let mut character = entity_gateway.new_character_by_user(&fake_user);
    character.character.name = utf8_to_utf16_array!("Test Char 1", 0x10);
    entity_gateway.set_character(&character);
    let mut character = entity_gateway.new_character_by_user(&fake_user);
    character.slot = 2;
    character.character.name = utf8_to_utf16_array!("Test Char 2", 0x10);
    entity_gateway.set_character(&character);

    let fake_user2 = UserAccount {
        id: 2,
        username: "hi2".to_string(),
        password: bcrypt::hash("qwer", 5).unwrap(),
        guildcard: Some(2),
        team_id: None,
        banned: false,
        muted_until: SystemTime::now(),
        created_at: SystemTime::now(),
        flags: 0,
    };
    entity_gateway.set_user(&fake_user2);
    entity_gateway.create_user_settings_by_user(&fake_user2);
    let mut character = entity_gateway.new_character_by_user(&fake_user2);
    character.character.name = utf8_to_utf16_array!("Test Char 3", 0x10);
    entity_gateway.set_character(&character);
    let mut character = entity_gateway.new_character_by_user(&fake_user2);
    character.slot = 2;
    character.character.name = utf8_to_utf16_array!("Test Char 4", 0x10);
    entity_gateway.set_character(&character);

    let fake_user3 = UserAccount {
        id: 3,
        username: "hi3".to_string(),
        password: bcrypt::hash("qwer", 5).unwrap(),
        guildcard: Some(3),
        team_id: None,
        banned: false,
        muted_until: SystemTime::now(),
        created_at: SystemTime::now(),
        flags: 0,
    };
    entity_gateway.set_user(&fake_user3);
    entity_gateway.create_user_settings_by_user(&fake_user3);
    let mut character = entity_gateway.new_character_by_user(&fake_user3);
    character.character.name = utf8_to_utf16_array!("Test Char 5", 0x10);
    entity_gateway.set_character(&character);
    let mut character = entity_gateway.new_character_by_user(&fake_user3);
    character.slot = 2;
    character.character.name = utf8_to_utf16_array!("Test Char 6", 0x10);
    entity_gateway.set_character(&character);

    let fake_user4 = UserAccount {
        id: 4,
        username: "hi4".to_string(),
        password: bcrypt::hash("qwer", 5).unwrap(),
        guildcard: Some(4),
        team_id: None,
        banned: false,
        muted_until: SystemTime::now(),
        created_at: SystemTime::now(),
        flags: 0,
    };
    entity_gateway.set_user(&fake_user4);
    entity_gateway.create_user_settings_by_user(&fake_user4);
    let mut character = entity_gateway.new_character_by_user(&fake_user4);
    character.character.name = utf8_to_utf16_array!("Test Char 7", 0x10);
    entity_gateway.set_character(&character);
    let mut character = entity_gateway.new_character_by_user(&fake_user4);
    character.slot = 2;
    character.character.name = utf8_to_utf16_array!("Test Char 8", 0x10);
    entity_gateway.set_character(&character);

    let patch_thread = thread::spawn(|| {
        info!("[patch] starting server");
        let patch_config = load_config();
        let patch_motd = load_motd();
        let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str());
        let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd);
        common::mainloop::mainloop(patch_state, patch_config.port);
    });
    let thread_entity_gateway = entity_gateway.clone();
    let auth_thread = thread::spawn(|| {
        info!("[auth] starting server");
        let auth_state = LoginServerState::new(thread_entity_gateway);
        common::mainloop::mainloop(auth_state, login::login::LOGIN_PORT);
    });
    let thread_entity_gateway = entity_gateway.clone();
    let char_thread = thread::spawn(|| {
        info!("[character] starting server");
        let char_state = CharacterServerState::new(thread_entity_gateway);
        common::mainloop::mainloop(char_state, login::character::CHARACTER_PORT);
    });
    let thread_entity_gateway = entity_gateway.clone();
    let ship_thread = thread::spawn(|| {
        info!("[ship] starting server");
        let ship_state = ShipServerState::new(thread_entity_gateway);
        common::mainloop::mainloop(ship_state, ship::ship::SHIP_PORT);
    });

    patch_thread.join().unwrap();
    auth_thread.join().unwrap();
    char_thread.join().unwrap();
    ship_thread.join().unwrap();
}