use crate::data_layer;
use chrono::{DateTime, Local, TimeZone, Utc};
use sqlite::Connection;

#[derive(Clone)]
pub struct Transaction {
    id: i64,
    account_id: i64,
    amount: f64,
    date: DateTime<Utc>,
    description: String,
    type_id: i64,
    asset_amount: f64,

    tr_type: TransactionType,
}

impl Transaction {
    pub fn new(
        id: i64,
        ac_id: i64,
        amount: f64,
        date: DateTime<Utc>,
        desc: String,
        type_id: i64,
        asset_amount: f64,
        con: &Connection,
    ) -> Self {
        Transaction {
            id: id,
            account_id: ac_id,
            amount: amount,
            date: date,
            description: desc,
            type_id: type_id,
            tr_type: data_layer::get_transaction_type(con, type_id).unwrap_or(TransactionType {
                id: 0,
                description: String::new(),
            }),
            asset_amount: asset_amount,
        }
    }

    pub fn new_empty() -> Self {
        Transaction {
            id: 0,
            account_id: 0,
            amount: 0.0,
            date: DateTime::from_timestamp(0, 0).unwrap_or_default(),
            description: "".to_string(),
            type_id: 0,
            tr_type: TransactionType::new(0, "".to_string()),
            asset_amount: 0.0,
        }
    }

    pub fn get_id(&self) -> i64 {
        return self.id;
    }

    pub fn get_amount(&self) -> f64 {
        return self.amount;
    }
    pub fn set_amount(&mut self, amnt: f64) {
        self.amount = amnt;
    }

    pub fn get_date(&self) -> DateTime<Local> {
        return Local.from_utc_datetime(&self.date.naive_local());
    }
    pub fn get_date_utc(&self) -> DateTime<Utc> {
        return self.date;
    }
    pub fn set_date(&mut self, date: DateTime<Local>) {
        self.date = date.to_utc();
    }

    pub fn get_desc(&self) -> String {
        return self.description.clone();
    }
    pub fn set_desc(&mut self, desc: String) {
        self.description = desc;
    }

    pub fn get_account_id(&self) -> i64 {
        return self.account_id;
    }
    pub fn set_account_id(&mut self, ac_id: i64) {
        self.account_id = ac_id;
    }

    pub fn get_type(&self) -> TransactionType {
        return self.tr_type.clone();
    }
    pub fn set_type(&mut self, tr_id: i64, con: &Connection) {
        self.type_id = tr_id;
        self.tr_type = data_layer::get_transaction_type(con, tr_id).unwrap_or(TransactionType {
            id: 0,
            description: String::new(),
        });
    }

    pub fn get_asset_amnt(&self) -> f64 {
        return self.asset_amount;
    }
    pub fn set_asset_amnt(&mut self, amnt: f64) {
        self.asset_amount = amnt;
    }
}

#[derive(Clone)]
pub struct TransactionType {
    id: i64,
    description: String,
}

impl TransactionType {
    pub fn new(id: i64, desc: String) -> Self {
        TransactionType {
            id: id,
            description: desc,
        }
    }
    pub fn get_id(&self) -> i64 {
        return self.id;
    }
    pub fn get_description(&self) -> String {
        return self.description.clone();
    }
}