mod login;
mod character;
mod dataaccess;
mod entities;

use std::thread;

use bcrypt;

use libpso::character::settings;
use libpso::character::character as pso_character;
use libpso::character::guildcard;

use entities::{UserAccount, UserSettings, Character, GuildCardData};
use dataaccess::DataAccess;
use elseware::utf8_to_utf16_array;

use login::LoginServerState;
use character::CharacterServerState;

use std::time::SystemTime;

#[derive(Clone)]
struct LoginStubData {
}

impl DataAccess for LoginStubData {
    fn get_user_by_name(&self, username: String) -> Option<UserAccount> {
        if username.as_str() == "hi" {
            Some(UserAccount {
                id: 1,
                username: "hi".to_owned(),
                password: bcrypt::hash("qwer", 5).unwrap(),
                guildcard: None,
                team_id: None,
                banned: false,
                muted_until: SystemTime::now(),
                created_at: SystemTime::now(),
            })
        }
        else {
            None
        }
    }

    fn get_user_settings_by_user(&self, user: &UserAccount) -> Option<UserSettings> {
        Some(UserSettings {
            id: 0,
            user_id: user.id,
            settings: settings::UserSettings::default()
        })
    }

    fn get_characters_by_user(&self, user: &UserAccount) -> [Option<Character>; 4] {
        let mut c = pso_character::Character::default();
        c.name = utf8_to_utf16_array!("Test Char", 16);
        [Some(Character {
            id: 1,
            user_id: user.id,
            character: c,
        }),
        None, None, None]
    }

    fn get_guild_card_data_by_user(&self, user: &UserAccount) -> GuildCardData {
        GuildCardData {
            id: 1,
            user_id: user.id,
            guildcard: guildcard::GuildCardData::default(),
        }
    }
}

fn main() {
    println!("[login+character] starting server");

    // TODO: character mainloop
    let auth_thread = thread::spawn(|| {
        let auth_state = LoginServerState::new(LoginStubData {});
        elseware::common::mainloop::mainloop(auth_state, login::LOGIN_PORT);
    });
    let char_thread = thread::spawn(|| {
        let char_state = CharacterServerState::new(LoginStubData {});
        elseware::common::mainloop::mainloop(char_state, character::CHARACTER_PORT);
    });

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