#include "catalog/widgets/ColumnPage.h"

#include "catalog/models/ColumnTableModel.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "util/PgLabTableView.h"
#include "ResultTableModelUtil.h"
#include "widgets/SqlCodePreview.h"
#include "SqlFormattingUtils.h"
#include "UserConfiguration.h"
#include "catalog/PgClass.h"
#include <QHeaderView>
#include <QSortFilterProxyModel>
#include <QStyledItemDelegate>
#include <QStringBuilder>
#include <unordered_set>

ColumnPage::ColumnPage(QWidget *parent)
	: QSplitter(Qt::Vertical, parent)
{
	m_tableView = new PgLabTableView(this);
	m_definitionView = new SqlCodePreview(this);
	addWidget(m_tableView);
	addWidget(m_definitionView);

	m_columnModel = new ColumnTableModel(this);
	m_sortFilterProxy = new QSortFilterProxyModel(this);
	m_sortFilterProxy->setSourceModel(m_columnModel);
	m_tableView->setItemDelegateForColumn(ColumnTableModel::TypeCol, new QStyledItemDelegate(this));
	m_tableView->setModel(m_sortFilterProxy);
    m_tableView->horizontalHeader()->setSortIndicator(ColumnTableModel::AttnumCol, Qt::AscendingOrder);
	m_tableView->setSortingEnabled(true);
	m_sortFilterProxy->sort(ColumnTableModel::AttnumCol, Qt::AscendingOrder);

	connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
			this, &ColumnPage::tableView_selectionChanged);
	connect(m_columnModel, &ColumnTableModel::modelReset, m_definitionView,	&SqlCodePreview::clear);
}

void ColumnPage::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &cls)
{
	m_catalog = cat;
	m_definitionView->setCatalog(cat);
	m_columnModel->setData(cat, cls);
	m_Class = cls;
	m_tableView->resizeColumnsToContents();
}

void ColumnPage::tableView_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
{
	auto&& indexes = m_tableView->selectionModel()->selectedIndexes();
	std::unordered_set<int> rijen;
	for (const auto &e : indexes)
		rijen.insert(m_sortFilterProxy->mapToSource(e).row());

    const QString alterTable = "ALTER TABLE " % m_Class->fullyQualifiedQuotedObjectName();

    QString completeSql;
    if (!rijen.empty()) {
        QString drops;
        QString addsql;
        auto iter = rijen.begin();
        if (iter != rijen.end())
        {
            auto && col = m_columnModel->column(*iter);
            drops   = alterTable % "\n  DROP COLUMN " % quoteIdent(col.name);
            addsql = alterTable % "\n  ADD COLUMN " % col.columnDefinition(*m_catalog);
            for (++iter; iter != rijen.end(); ++iter)
            {
                auto && col = m_columnModel->column(*iter);
                drops += ",\n  DROP COLUMN " % quoteIdent(col.name);
                addsql += ",\n  ADD COLUMN " % col.columnDefinition(*m_catalog);
            }
            drops += ";";
            addsql += ";";
            m_definitionView->setPlainText(drops % "\n\n" % addsql);
            completeSql += drops % "\n\n" % addsql % "\n\n";
        }
        for (auto r : rijen)
        {
            auto && col = m_columnModel->column(r);
            auto cs = col.commentStatement(*m_catalog, m_Class.value());
            if (!cs.isEmpty())
                completeSql += cs % "\n";
        }

        completeSql += "\n-- SQL to correct just the defaults\n";
        for (auto r : rijen)
        {
            auto && col = m_columnModel->column(r);
            completeSql += alterTable % " ALTER COLUMN " % quoteIdent(col.name);
            if (col.hasdef)
                completeSql += " SET DEFAULT " % col.defaultValue % ";\n";
            else
                completeSql += " DROP DEFAULT;\n";
        }
        completeSql += "\n-- SQL to correct NULLABLE\n";
        for (auto r : rijen)
        {
            auto && col = m_columnModel->column(r);
            completeSql += alterTable % " ALTER COLUMN " % quoteIdent(col.name);
            if (col.notnull)
                completeSql += " SET NOT NULL;\n";
            else
                completeSql += " DROP NOT NULL;\n";
        }
    }
    m_definitionView->setPlainText(completeSql);
}
