use crate::{
    commands::{Config, Result, not_available},
    entities::{Bill, Limit},
    jobber::Jobber,
    views::ApplyTableStyle,
};
use color_print::cwriteln;
use tabled::{
    Table, Tabled,
    settings::{Alignment, Width, object::Columns},
};

#[derive(Tabled)]
pub(crate) struct BillView {
    #[tabled(rename = "Pos")]
    pub(crate) pos: usize,
    #[tabled(rename = "Worker")]
    pub(crate) worker: String,
    #[tabled(rename = "Subject")]
    pub(crate) subject: String,
    #[tabled(rename = "Rate")]
    pub(crate) rate: String,
    #[tabled(rename = "Interval")]
    pub(crate) interval: String,
    #[tabled(rename = "Work")]
    pub(crate) worked: String,
    #[tabled(rename = "Price")]
    pub(crate) revenue: String,
}

impl BillView {
    pub(crate) fn new(pos: usize, bill: &Bill, database: &impl Jobber, ansi: bool) -> Result<Self> {
        let scheme = &bill.scheme;
        Ok(Self {
            pos,
            worker: database.get_full_worker_name(&bill.worker)?,
            subject: bill.subject.clone(),
            rate: scheme
                .rate
                .clone()
                .map_or(not_available(ansi), |p| p.to_string()),
            interval: scheme.format_duration(
                bill.scheme.min_work_interval.duration(),
                Limit::None,
                ansi,
            ),
            worked: scheme.format_duration(bill.worked(), Limit::None, ansi),
            revenue: scheme.format_revenue(bill.worked(), ansi),
        })
    }
}

pub(crate) fn create_bill_table(
    config: &Config,
    rows: impl IntoIterator<Item = BillView>,
) -> Table {
    let mut table = Table::new(rows);
    table.modify(Columns::first(), Alignment::right());
    table.modify(Columns::one(2), Width::wrap(40));
    table.modify(Columns::one(3), Alignment::right());
    table.modify(Columns::one(4), Alignment::right());
    table.modify(Columns::one(5), Alignment::right());
    table.modify(Columns::one(6), Alignment::right());
    table.style(&config.table_style);
    table
}

impl std::fmt::Display for BillView {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        cwriteln!(f, "          Pos: {}", self.pos)?;
        cwriteln!(f, "       Worker: <s>{}</>", self.worker)?;
        if !self.subject.is_empty() {
            cwriteln!(f, "      Subject: <i>{}</>", &self.subject)?;
        }
        if !self.worked.is_empty() {
            if !self.rate.is_empty() {
                cwriteln!(f, "         Rate: {}", self.rate)?;
            }
            cwriteln!(f, "     Interval: {}", self.interval)?;
            cwriteln!(f, "         Work: {}", self.worked)?;
            cwriteln!(f, "      Revenue: {}", self.revenue)?;
        }
        Ok(())
    }
}
