#include "CatalogTablesPage.h"

#include "catalog/widgets/CatalogConstraintPage.h"
#include "catalog/widgets/CatalogIndexPage.h"
#include "catalog/widgets/ColumnPage.h"
#include "catalog/widgets/DependantsPage.h"
#include "PropertiesPage.h"
#include "catalog/widgets/TriggerPage.h"
#include "catalog/models/ColumnTableModel.h"
#include "catalog/models/ConstraintModel.h"
#include "catalog/tables/TablesTableModel.h"
#include "util/PgLabTableView.h"
#include "ResultTableModelUtil.h"
#include "widgets/SqlCodePreview.h"
#include "SqlFormattingUtils.h"
#include "catalog/PgAttributeContainer.h"
#include "catalog/PgIndexContainer.h"
#include "catalog/PgTriggerContainer.h"

#include <QApplication>
#include <QHeaderView>
#include <QStringBuilder>
//#include <QSortFilterProxyModel>
#include <QTableWidget>

CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget *parent)
	: QSplitter(Qt::Horizontal, parent)
    , m_tablesTableView(this, new TablesTableModel(opendatabase, this))
{
    auto tv = m_tablesTableView.itemView();
    tv->setSelectionMode(QAbstractItemView::SingleSelection);
	m_detailsTabs = new QTabWidget(this);

	// Populate splitter
    addWidget(tv);
	addWidget(m_detailsTabs);

	// - Columns page
	m_columnsPage = new ColumnPage(this);
	m_detailsTabs->addTab(m_columnsPage, "");

	// constrainst
	m_constraintPage = new CatalogConstraintPage(this);
	m_detailsTabs->addTab(m_constraintPage, "");

	// - Index page
	m_indexPage = new CatalogIndexPage(this);
	m_detailsTabs->addTab(m_indexPage, "");

	// - Properties page
//    m_propertiesPage = new PropertiesPage(this);
//    m_propertiesPage->setSourceModel(m_tablesTableView.dataModel());
//    m_detailsTabs->addTab(m_propertiesPage, "");

	// - Trigger page
	m_triggerPage = new TriggerPage(this);
	m_detailsTabs->addTab(m_triggerPage, "");

	m_dependentsPage = new DependantsPage(this);
	m_detailsTabs->addTab(m_dependentsPage, "");

	// SQL tab
	m_tableSql = new SqlCodePreview(this);
	m_detailsTabs->addTab(m_tableSql, "");

	// Force focus on columns tab by default
	m_detailsTabs->setCurrentIndex(0);

	// Signals
    connect(tv->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
			&CatalogTablesPage::tableListTable_currentRowChanged);

    connect(m_tablesTableView.dataModel(), &QAbstractItemModel::layoutChanged,
			this, &CatalogTablesPage::tableListTable_layoutChanged);

    connect(tv, &QTableView::doubleClicked,
			this, &CatalogTablesPage::on_tableListTable_doubleClicked);
}

void CatalogTablesPage::retranslateUi(bool /*all*/)
{
	auto set_tabtext = [this] (QWidget *widget, QString translation) {
		m_detailsTabs->setTabText(m_detailsTabs->indexOf(widget), translation);
	};

	set_tabtext(m_columnsPage, QApplication::translate("TablesPage", "Columns", nullptr));
	set_tabtext(m_constraintPage, QApplication::translate("TablesPage", "Constraints", nullptr));
	set_tabtext(m_indexPage, QApplication::translate("TablesPage", "Indexes", nullptr));
//	set_tabtext(m_propertiesPage, QApplication::translate("TablesPage", "Properties", nullptr));
	set_tabtext(m_triggerPage, QApplication::translate("TablesPage", "Triggers", nullptr));
	set_tabtext(m_dependentsPage, QApplication::translate("TablesPage", "Dependants", nullptr));
	set_tabtext(m_tableSql, QApplication::translate("TablesPage", "SQL", nullptr));
}

void CatalogTablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
{
	m_catalog = cat;
    m_tablesTableView.setCatalog(cat);

	m_constraintPage->setCatalog(cat);
	m_indexPage->setCatalog(cat);
	m_triggerPage->setCatalog(cat);
	m_dependentsPage->setCatalog(cat);
}

void CatalogTablesPage::setNamespaceFilter(NamespaceFilter filter)
{
    m_tablesTableView.dataModel()->setNamespaceFilter(filter);
    //m_tablesTableView.tableView()->resizeColumnsToContents();
}

void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
    if (current.row() == previous.row())
        return;

    auto tableNode = TablesTableModel::nodeFromIndex(m_tablesTableView.sortFilter()->mapToSource(current)); // m_tablesTableView.rowItemForProxyIndex(current);
    selectedTableChanged(tableNode->_class);
}


void CatalogTablesPage::tableListTable_layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint )
{
    auto table = m_tablesTableView.currentRowItem();
    selectedTableChanged(table);
}

void CatalogTablesPage::on_tableListTable_doubleClicked(const QModelIndex &index)
{
    auto sourceIndex = m_tablesTableView.sortFilter()->mapToSource(index);
    auto tableNode = TablesTableModel::nodeFromIndex(sourceIndex);
    if (tableNode)
    {
        Oid oid = tableNode->_class.oid();
        if (oid != InvalidOid) {
            tableSelected(oid);
        }
    }
}

void CatalogTablesPage::selectedTableChanged(const std::optional<PgClass> &table)
{
	m_columnsPage->setData(m_catalog, table);

	m_constraintPage->setFilter(table);
	m_indexPage->setFilter(table);
	m_triggerPage->setFilter(table);
	m_dependentsPage->setFilter(table);

	updateSqlTab(table);
}

void CatalogTablesPage::updateSqlTab(const std::optional<PgClass> &table)
{
	if (!table.has_value()) {
		m_tableSql->clear();
		return;
	}

	QString drop_sql;
	QString create_sql;
    // table
    drop_sql += table->dropSql() % "\n";
    create_sql += table->createSql() % "\n";
	// - columns
	// - constraints
	// table details (inherits etc)

	// Indexes
	auto && indexes = m_catalog->indexes()->getIndexesForTable(table->oid());
    if (!indexes.empty()) {
        drop_sql += "-- drop Indexes\n";
        create_sql += "-- create Indexes\n";
        for (auto && index : indexes) {
            drop_sql += index.dropSql() % "\n";
            create_sql += index.createSql() % "\n";
        }
    }

	// Triggers
    auto && triggers = m_catalog->triggers()->getTriggersForRelation(table->oid());
    if (!triggers.empty()) {
        drop_sql += "-- drop Triggers\n";
        create_sql += "-- create Triggers\n";
        for (auto && trg : triggers) {
            drop_sql += trg.dropSql() % "\n";
            create_sql += trg.createSql() % "\n";
        }
    }

	// Privileges
	create_sql += "-- set Privileges\n";
	create_sql += table->grantSql() % "\n";

	// Comments
	create_sql += "-- set Comments table + columns\n";
    create_sql += table->commentSql() % "\n";

    auto && cols = m_catalog->attributes()->getColumnsForRelation(table->oid());
    for (auto && col : cols) {
        if (!col.description.isEmpty()) {
            create_sql += "COMMENT ON COLUMN " + table->fullyQualifiedQuotedObjectName()
                    + "." + quoteIdent(col.name) + " IS " + dollarQuoteString(col.description) + ";\n";
        }
    }

    //
	m_tableSql->setPlainText(drop_sql % "\n\n" % create_sql);
}
