#include "CrudTab.h"
#include "ui_CrudTab.h"
#include "CrudModel.h"
#include "CustomDataRole.h"
#include "ResultTableModelUtil.h"
#include "util/PgLabItemDelegate.h"
#include "IntegerRange.h"
#include "OpenDatabase.h"
#include "catalog/PgClassContainer.h"
#include "catalog/PgDatabaseCatalog.h"
#include <QDebug>
#include <QMenu>
#include <QMessageBox>
#include <iterator>
#include <set>


CrudTab::CrudTab(IDatabaseWindow *context, QWidget *parent)
	: QWidget(parent)
	, ui(new Ui::CrudTab)
    , m_context(context)
{
	ui->setupUi(this);

	m_db = context->openDatabase();

	SetTableViewDefault(ui->tableView);

	auto delegate = new PgLabItemDelegate(ui->tableView);
	ui->tableView->setItemDelegate(delegate);

    m_crudModel = new CrudModel(nullptr);

    m_SortFilterProxy = new QSortFilterProxyModel(this);
    m_SortFilterProxy->setSourceModel(m_crudModel);
    m_SortFilterProxy->setSortRole(CustomSortRole);
    ui->tableView->setModel(m_SortFilterProxy);
    ui->tableView->setSortingEnabled(true);
    m_SortFilterProxy->sort(0, Qt::AscendingOrder);

	ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
	ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
	ui->tableView->addAction(ui->actionRemove_rows);

	auto horizontal_header = ui->tableView->horizontalHeader();
	horizontal_header->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
	connect(horizontal_header, &QHeaderView::customContextMenuRequested,
			this, &CrudTab::headerCustomContextMenu);

}

CrudTab::~CrudTab()
{
    delete m_crudModel;
	delete ui;
}

void CrudTab::setConfig(Oid oid) //std::shared_ptr<OpenDatabase> db, const PgClass &table)
{
	m_table = *m_db->catalog()->classes()->getByKey(oid);
	m_crudModel->setConfig(m_db, *m_table);
	m_context->setTitleForWidget(this, m_table->objectName(), "");
}

void CrudTab::refresh()
{
	m_crudModel->loadData();
}

void CrudTab::on_actionRemove_rows_triggered()
{
	std::set<IntegerRange<int>> row_ranges;
    auto selection = m_SortFilterProxy->mapSelectionToSource(ui->tableView->selectionModel()->selection());
    for (auto& range : selection) {
		row_ranges.emplace(range.top(), range.height());
	}
	std::set<IntegerRange<int>> merged_ranges;
	merge_ranges(row_ranges.begin(), row_ranges.end(), std::inserter(merged_ranges, merged_ranges.begin()));

	QString msg = tr("Are you certain you want to remove the following row(s)?");
	msg += "\n";
	bool first = true;
	for (auto range : merged_ranges) {
		if (first) first = false;
		else msg += ", ";

		auto s = range.start() + 1, e = range.end();
		if (s == e)
			msg += QString("%1").arg(s);
		else
			msg += QString("%1 through %2").arg(s).arg(e);

		msg += " ";
	}
	auto res = QMessageBox::question(this, "pgLab",	msg, QMessageBox::Yes, QMessageBox::No);

	if (res == QMessageBox::Yes) {
		auto [res, msg] = m_crudModel->removeRows(merged_ranges);
		if (!res) {
			QMessageBox::critical(this, "pgLab", msg, QMessageBox::Close);
		}
	}
}

void CrudTab::headerCustomContextMenu(const QPoint &pos)
{
    if (!headerContextMenu)
        buildHeaderContextMenu();


    if (headerContextMenu)
    {
        auto horizontal_header = ui->tableView->horizontalHeader();
        headerContextMenu->popup(horizontal_header->mapToGlobal(pos));
    }
}

void CrudTab::gotoColumn(QString column)
{
    for (int i = 1; i < m_crudModel->columnCount(); ++i)
    {
        auto name = m_crudModel->headerData(i, Qt::Horizontal).toString();
        if (name == column)
        {
            auto index = ui->tableView->currentIndex();
            index = ui->tableView->model()->index(index.row(), i);
            ui->tableView->setCurrentIndex(index);
            break;
        }
    }
}

void CrudTab::buildHeaderContextMenu()
{
    delete headerContextMenu;
    headerContextMenu = new QMenu(this);
    auto columnMenu = headerContextMenu->addMenu("Go to column");

    std::vector<QString> columnNames;
    for (int i = 1; i < m_crudModel->columnCount(); ++i)
        columnNames.push_back(m_crudModel->headerData(i, Qt::Horizontal).toString());

    std::sort(columnNames.begin(), columnNames.end());
    for (auto& columnName : columnNames)
    {
        auto action = new QAction(columnName, this);
        columnMenu->addAction(action);
        connect(action, &QAction::triggered, this,
            [this, columnName] ()
            {
                gotoColumn(columnName);
            }
        );
    }
}
