use std::fmt;
use std::fmt::Display;

use crate::write_utils::Indent;
use derive_more::derive::From;

use super::query::{dml::DML, SQLQuery, TableReference};

#[derive(From, Debug, Clone, PartialEq, Eq)]
pub enum Statement {
    SQLQuery(SQLQuery),
    DML(DML),
}

impl Statement {
    pub fn fmt_indented(
        &self,
        f: &mut std::fmt::Formatter<'_>,
        indentation: Indent,
    ) -> std::fmt::Result {
        match self {
            Statement::SQLQuery(query) => query.fmt_indented(f, indentation),
            Statement::DML(dml) => dml.fmt_indented(f, indentation),
        }
    }

    pub fn to_compact_sql(&self) -> String {
        struct Compact<'a>(&'a Statement);
        impl fmt::Display for Compact<'_> {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                self.0.fmt_indented(f, Indent::Compact)
            }
        }
        Compact(self).to_string()
    }

    pub fn get_table_references(&self) -> Vec<TableReference> {
        match self {
            Statement::SQLQuery(query) => query.get_table_references(),
            Statement::DML(DML::Insert(ins)) => ins.query.get_table_references(),
            Statement::DML(DML::Merge(mrg)) => mrg.query.get_table_references(),
        }
    }
}

impl Default for Statement {
    fn default() -> Self {
        Statement::SQLQuery(SQLQuery::default())
    }
}

impl Display for Statement {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.fmt_indented(f, Indent::default())
    }
}
