#include "databaseview.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QSettings>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QSqlError>
#include <QDebug>
#include <iostream>

const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"};

SelectColumnsDialog::SelectColumnsDialog(QWidget *parent) : QDialog(parent)
{
    m_listWidget = new QListWidget(this);
    m_listWidget->setSelectionMode(QAbstractItemView::MultiSelection);
    QVBoxLayout *layout = new QVBoxLayout(this);
    setLayout(layout);
    layout->addWidget(m_listWidget);

    QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
    connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
    layout->addWidget(buttonBox);

    setWindowTitle(tr("Select columns"));
}

void SelectColumnsDialog::setColumns(QStringList columns)
{
    QSettings settings;
    m_listWidget->addItems(columns);
    QStringList selected = settings.value("databaseview/selectedColumns", DEFAULT_COLUMNS).toStringList();
    for(auto &sel : selected)
    {
        int i = columns.indexOf(sel);
        if(i>=0)
            m_listWidget->item(i)->setSelected(true);
    }
}

QStringList SelectColumnsDialog::selectedColumns()
{
    QStringList ret;
    for(auto &sel : m_listWidget->selectedItems())
        ret.append(sel->text());
    return ret;
}

FITSFileModel::FITSFileModel(QObject *parent) : QSqlQueryModel(parent)
{

}

void FITSFileModel::sort(int column, Qt::SortOrder order)
{
    if(column < 0)
        m_sort.clear();
    else if(column <= m_columns.size())
    {
        if(column == 0)m_sort = " ORDER BY f.file ";
        else m_sort = QString(" ORDER BY \"h%1_value\" ").arg(column-1);
        m_sort += order == Qt::AscendingOrder ? "ASC" : "DESC";
        prepareQuery();
    }
}

void FITSFileModel::setColumns(const QStringList &columns)
{
    m_columns = columns;
    prepareQuery();
}

void FITSFileModel::setFilter(const QStringList &key, const QStringList &value)
{
    if(value.isEmpty())
    {
        m_key.clear();
        m_value.clear();
    }
    else
    {
        m_key = key;
        m_value = value;
    }
    prepareQuery();
}

void FITSFileModel::prepareQuery()
{
    QString cols;
    QString join;
    QString where;
    QString sql = "SELECT f.file,";
    for(int i=0; i<m_value.size(); i++)
    {
        if(m_key[i] == "file")
            where = QString(" WHERE f.file LIKE '%1'").arg(m_value[i]);
        else
            join += QString(" JOIN fits_headers AS s%1 ON f.id=s%1.id_file AND s%1.key='%2' AND s%1.value LIKE '%3'").arg(i).arg(m_key[i]).arg(m_value[i]);
    }
    int i=0;
    for(auto &column : m_columns)
    {
        cols += QString("GROUP_CONCAT(h%1.value) AS h%1_value,").arg(i);
        join += QString(" LEFT JOIN fits_headers AS h%1 ON f.id=h%1.id_file AND h%1.key='%2'").arg(i).arg(column);
        i++;
    }
    cols.chop(1);
    sql += cols;
    sql += " FROM fits_files AS f";
    sql += join;
    sql += where;
    sql += " GROUP BY f.id" + m_sort;
    setQuery(sql);
    setHeaderData(0, Qt::Horizontal, tr("File name"));
    i = 1;
    for(auto &column : m_columns)
    {
        setHeaderData(i++, Qt::Horizontal, column);
    }
    std::cout << sql.toStdString() << std::endl;
    if(lastError().type() != QSqlError::NoError)
        qDebug() << lastError();
}

DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent)
  ,m_database(database)
{
    QVBoxLayout *layout = new QVBoxLayout(this);
    setLayout(layout);

    m_tableView = new QTableView(this);
    m_tableView->verticalHeader()->setDefaultSectionSize(1);
    m_tableView->setSortingEnabled(true);
    m_tableView->horizontalHeader()->setSortIndicatorShown(true);
    layout->addWidget(m_tableView);
    connect(m_tableView, &QTableView::activated, this, &DataBaseView::itemActivated);

    m_model = new FITSFileModel(this);

    QSettings settings;
    m_tableView->setModel(m_model);
    m_model->setColumns(settings.value("databaseview/selectedColumns", DEFAULT_COLUMNS).toStringList());
    m_tableView->horizontalHeader()->restoreState(settings.value("databaseview/header").toByteArray());

    QHBoxLayout *hlayout = new QHBoxLayout();
    layout->addLayout(hlayout);

    QPushButton *selectColumnsButton = new QPushButton(tr("Select columns"), this);
    hlayout->addWidget(selectColumnsButton);
    connect(selectColumnsButton, &QPushButton::pressed, this, &DataBaseView::selectColumns);

    for(int i=0; i<3; i++)
    {
        m_filterKeyword[i] = new QComboBox(this);
        m_filterKeyword[i]->addItem("file");
        m_filterKeyword[i]->addItems(m_database->getFitsKeywords());
        m_search[i] = new QLineEdit(this);
        m_search[i]->setPlaceholderText(tr("Text to search, you can % as wildcard"));
        connect(m_search[i], &QLineEdit::returnPressed, this, &DataBaseView::applyFilter);
        hlayout->addWidget(m_filterKeyword[i]);
        hlayout->addWidget(m_search[i]);
    }

    QPushButton *filterButton = new QPushButton(tr("Filter"), this);
    connect(filterButton, SIGNAL(pressed()), this, SLOT(applyFilter()));
    hlayout->addWidget(filterButton);
}

DataBaseView::~DataBaseView()
{
    QSettings settings;
    settings.setValue("databaseview/header", m_tableView->horizontalHeader()->saveState());
}

void DataBaseView::selectColumns()
{
    SelectColumnsDialog dialog;
    QStringList columns = m_database->getFitsKeywords();
    dialog.setColumns(columns);
    if(dialog.exec() == QDialog::Accepted)
    {
        QSettings settings;
        QStringList columns = dialog.selectedColumns();
        settings.setValue("databaseview/selectedColumns", columns);
        m_model->setColumns(columns);
    }
}

void DataBaseView::loadDatabase()
{
    QSettings settings;
    m_model->setColumns(settings.value("databaseview/selectedColumns", DEFAULT_COLUMNS).toStringList());
}

void DataBaseView::itemActivated(const QModelIndex &index)
{
    emit loadFile(m_model->data(index.siblingAtColumn(0)).toString());
}

void DataBaseView::applyFilter()
{
    QStringList keys;
    QStringList values;
    for(int i=0; i<3; i++)
    {
        QString key = m_filterKeyword[i]->currentText();
        if(!m_search[i]->text().isEmpty() && !keys.contains(key))
        {
            keys.append(key);
            values.append(m_search[i]->text());
        }
    }
    m_model->setFilter(keys, values);
}

