use std::{convert::TryFrom, error::Error};

use sqlite::Connection;

use crate::data_layer;

#[derive(Clone)]
pub struct Account {
    id: i64,
    name: String,
    asset_price: f64,
    ac_type: AccountType,
}

impl Account {
    pub fn new(id: i64, name: String, asset_price: f64, ac_type: AccountType) -> Self {
        Account {
            id: id,
            name: name,
            asset_price: asset_price,
            ac_type: ac_type,
        }
    }
    pub fn new_empty() -> Self {
        return Account {
            id: 0,
            name: String::new(),
            asset_price: 0.0,
            ac_type: AccountType::Cash,
        };
    }
    pub fn get_id(&self) -> i64 {
        return self.id;
    }
    pub fn get_name(&self) -> String {
        return self.name.clone();
    }
    pub fn set_name(&mut self, name: String) {
        self.name = name;
    }
    pub fn get_asset_price(&self) -> f64 {
        return self.asset_price;
    }
    pub fn set_asset_price(&mut self, asset_price: f64) {
        self.asset_price = asset_price;
    }
    pub fn get_ac_type(&self) -> AccountType {
        match AccountType::try_from(self.ac_type as i64) {
            Ok(at) => return at,
            Err(_) => AccountType::Cash,
        }
    }
    pub fn set_type(&mut self, ac_type: AccountType) {
        self.ac_type = ac_type;
    }
    pub fn get_total(&self, con: &Connection) -> Result<f64, Box<dyn Error>> {
        return data_layer::get_account_total(self.id, con);
    }
}

#[derive(Copy, Clone)]
pub enum AccountType {
    Cash = 1,
    Assets,
}
impl AccountType {
    pub fn from_usize(v: usize) -> Self {
        const CASH: usize = AccountType::Cash as usize;
        const ASSET: usize = AccountType::Assets as usize;
        match v {
            CASH => return Self::Cash,
            ASSET => return Self::Assets,
            _ => return Self::Cash,
        }
    }
}

impl TryFrom<i64> for AccountType {
    type Error = ();

    fn try_from(v: i64) -> Result<Self, Self::Error> {
        match v {
            x if x == AccountType::Cash as i64 => Ok(AccountType::Cash),
            x if x == AccountType::Assets as i64 => Ok(AccountType::Assets),
            _ => Ok(AccountType::Cash),
        }
    }
}