//! Creates [`Tables`](ratatui::widgets::Table) from [`Relations`](Relation) or [`Fields`](Field).
use ratatui::layout::Constraint;
use ratatui::style::{Modifier, Style, Styled, Stylize};
use ratatui::text::Span;
use ratatui::widgets::{Cell, Row, Table};

use crate::fields::Field;
use crate::relations::Relation;
use crate::ui::sidebar::MIN_COLUMN_WIDTH;

/// Make the relation table given a set of [`Relations`](Relation).
pub fn make_relation_table<'a>(relations: &[Relation]) -> Option<Table<'a>> {
    if relations.is_empty() {
        None
    } else {
        let mut col_widths = [1; 4];
        let mut rows: Vec<Row> = vec![];
        let selected_style = Style::default().add_modifier(Modifier::REVERSED);

        for relation in relations {
            if relation.name.len() > col_widths[0] {
                col_widths[0] = relation.name.len();
            }
            if relation.relation_type.to_string().len() > col_widths[1] {
                col_widths[1] = relation.relation_type.to_string().len();
            }
            if relation.owner.len() > col_widths[2] {
                col_widths[2] = relation.owner.len();
            }
            if relation.schema.len() > col_widths[3] {
                col_widths[3] = relation.owner.len();
            }

            rows.push(Row::new(vec![
                relation.name.clone(),
                relation.relation_type.to_string(),
                relation.owner.clone(),
                relation.schema.clone(),
            ]));
        }

        Some(
            Table::new(
                rows,
                Constraint::from_lengths(col_widths.into_iter().map(|x| {
                    if x <= MIN_COLUMN_WIDTH.into() {
                        MIN_COLUMN_WIDTH
                    } else {
                        x as u16
                    }
                })),
            )
            .header(Row::new(
                Relation::struct_fields()
                    .iter()
                    .map(|x| x.clone().underlined())
                    .collect::<Vec<Span>>(),
            ))
            .row_highlight_style(selected_style),
        )
    }
}

/// Make the data table given a set of Vec<[`Fields`](Field)>.
pub fn make_data_table<'a>(fields: &[Vec<Field>]) -> Option<Table<'a>> {
    if fields.is_empty() {
        return None;
    }

    let mut num_cols: usize = 0;
    let rows = fields
        .iter()
        .map(|row| {
            num_cols = row.len();
            let mut values = vec![];
            for field in row {
                let value = match &field.toml_value {
                    Some(v) => {
                        if let Some(w) = v.as_array() {
                            let mut trimmed = vec![];
                            for item in w.iter() {
                                trimmed.push(format!("{item}").trim_matches('"').to_string());
                            }
                            Cell::new(trimmed.join(","))
                        } else {
                            Cell::new(format!("{v}").trim_matches('"').to_string())
                        }
                    }
                    .set_style(Style::default()),
                    None => if field.parse_error {
                        Cell::new("?").red()
                    } else {
                        Cell::new("NULL")
                    }
                    .dim(),
                };
                values.push(value);
            }
            Row::new(values)
        })
        .collect::<Vec<Row>>();

    // Not sure how to scroll a table, if it's even possible,
    // so need to limit number of columns.
    if num_cols > 10 {
        num_cols = 10;
    }

    let selected_style = Style::default().reversed();
    Some(
        Table::new(rows, vec![Constraint::Fill(1); num_cols])
            .row_highlight_style(selected_style)
            .column_highlight_style(selected_style)
            .header(Row::new(
                fields[0]
                    .iter()
                    .map(|f| f.name.clone())
                    .collect::<Vec<String>>(),
            )),
    )
}
