/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "configuration.h"
#include <QStandardPaths>
#include <fstream>
#include <boost/algorithm/string/predicate.hpp>
#include <iostream>
#include <QCoreApplication>
#include "defaults.h"

namespace po = boost::program_options;

inline std::string defaultUserConfigLocation()
{
#ifdef ConfigPath
    return ConfigPath;
#else
    // try to locate an existing config
    QString path = QStandardPaths::locate(QStandardPaths::ConfigLocation, "smolbote/smolbote.cfg");

    // it's possible there is no config, so set the path properly
    if(path.isEmpty())
        path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/smolbote/smolbote.cfg";

    return path.toStdString();
#endif
}

Configuration::Configuration(QObject *parent)
    : QObject(parent)
    , m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString())
{
    commandLine_desc.add_options()
        ("help,h", "Display this help.")
        ("version,v", "Display version information.")
        ("build", "Display build branch and commit.")

        ("config,c", po::value<std::string>()->default_value(defaultUserConfigLocation()), "Set the configuration file.")
        ("no-remote", "Do not accept or send remote commands.")

        ("args", po::value<std::vector<std::string>>(), "Command(s) and/or URL(s).")
        ;

    arguments_desc.add("args", -1);

    configuration_desc.add_options()
        ("browser.stylesheet", po::value<std::string>())
        ("browser.session", po::value<std::string>(), "Load session data from specified arg.")
        ("browser.locale", po::value<std::string>(), "Set Qt localization.")
        ("browser.translation", po::value<std::string>(), "Set application localization.")

        // main window ui
        ("mainwindow.height", po::value<int>()->default_value(720))
        ("mainwindow.width", po::value<int>()->default_value(1280))
        ("mainwindow.maximized", po::value<bool>()->default_value(true))
        ("mainwindow.title", po::value<std::string>()->default_value("smolbote"))

        // main window shortcuts
        ("mainwindow.shortcuts.newGroup", po::value<std::string>()->default_value("Ctrl+G"))
        ("mainwindow.shortcuts.newWindow", po::value<std::string>()->default_value("Ctrl+N"))

        ("mainwindow.shortcuts.about", po::value<std::string>()->default_value("Ctrl+H"))
        ("mainwindow.shortcuts.quit", po::value<std::string>()->default_value("Ctrl+Q"))

        ("mainwindow.shortcuts.search", po::value<std::string>()->default_value("F3"))
        ("mainwindow.shortcuts.tileWindows", po::value<std::string>()->default_value("F9"))
        ("mainwindow.shortcuts.cascadeWindows", po::value<std::string>()->default_value("F10"))

        // navigation
        ("navigation.movable", po::value<bool>()->default_value(false))
        ("navigation.shortcuts.back", po::value<std::string>()->default_value("Ctrl+Left"))
        ("navigation.shortcuts.backMenu", po::value<std::string>()->default_value("Ctrl+Down"))
        ("navigation.shortcuts.forward", po::value<std::string>()->default_value("Ctrl+Right"))
        ("navigation.shortcuts.forwardMenu", po::value<std::string>()->default_value("Ctrl+Up"))
        ("navigation.shortcuts.refresh", po::value<std::string>()->default_value("F5"))
        ("navigation.shortcuts.reload", po::value<std::string>()->default_value("Ctrl+F5"))
        ("navigation.shortcuts.home", po::value<std::string>()->default_value("Ctrl+Home"))

        // address bar
        ("addressbar.shortcuts.focus", po::value<std::string>()->default_value("F4"))
        ("addressbar.shortcuts.menu", po::value<std::string>()->default_value("F2"))

        // subwindow
        ("subwindow.shortcuts.menu", po::value<std::string>()->default_value("F1"))
        ("subwindow.shortcuts.new", po::value<std::string>()->default_value("Ctrl+T"))
        ("subwindow.shortcuts.close", po::value<std::string>()->default_value("Ctrl+X"))
        ("subwindow.shortcuts.left", po::value<std::string>()->default_value("Ctrl+O"))
        ("subwindow.shortcuts.moveLeft", po::value<std::string>()->default_value("Ctrl+Shift+O"))
        ("subwindow.shortcuts.right", po::value<std::string>()->default_value("Ctrl+P"))
        ("subwindow.shortcuts.moveRight", po::value<std::string>()->default_value("Ctrl+Shift+P"))
        ("subwindow.shortcuts.fullscreen", po::value<std::string>()->default_value("F11"))

        // Filter settings
        ("filter.path", po::value<std::string>()->default_value(FilterPath))
        ("filter.adblock", po::value<std::string>())
        ("filter.header", po::value<std::vector<std::string>>())
//        ("filter.cookies.block.all", po::value<bool>()->default_value(false))
//        ("filter.cookies.block.thirdParty", po::value<bool>()->default_value(true))
//        ("filter.cookies.path", po::value<std::string>()->default_value("~/.config/smolbote/cookies.d"))

        // Plugin settings
        ("plugins.path", po::value<std::string>()->default_value(PluginsPath))

        // Profile settings
        // default profile name the browser should use; "" is off-the-record
        ("profile.default", po::value<std::string>()->default_value(""))
        ("profile.path", po::value<std::string>()->default_value(ProfilesPath))
        ("profile.search", po::value<std::string>()->default_value("https://duckduckgo.com/?q=%1&ia=web"))
        ("profile.homepage", po::value<std::string>()->default_value("about:blank"))
        ("profile.newtab", po::value<std::string>()->default_value("about:blank"))

        // Bookmark settings
        ("bookmarks.path", po::value<std::string>()->default_value(BookmarksPath))
        ("bookmarks.shortcut", po::value<std::string>()->default_value("Ctrl+B"))

        // Downloads settings
        ("downloads.path", po::value<std::string>()->default_value(DownloadsPath))
        ("downloads.shortcut", po::value<std::string>()->default_value("Ctrl+D"))
        ;
}

bool Configuration::parse(const std::string &path)
{
    std::ifstream f(path, std::ifstream::in);

    // parse_config_file(file, options_description, allow_unregistered)
    po::store(po::parse_config_file(f, configuration_desc, true), vm);
    return true;
}

bool Configuration::parse(int argc, char **argv)
{
    try {
        auto cmd = po::command_line_parser(argc, argv);
        po::options_description desc;
        desc.add(commandLine_desc).add(configuration_desc);
        cmd.options(desc);
        cmd.positional(arguments_desc);
        po::store(cmd.run(), vm);
    } catch(const po::error &e) {
        qWarning("Error parsing command line: %s", e.what());
        return false;
    }

    return true;
}

QHash<QString, QString> Configuration::section(const std::string &prefix) const
{
    QHash<QString, QString> v;
    for(auto &s : configuration_desc.options()) {
        if(boost::starts_with(s->long_name(), prefix)) {
            v[s->long_name().c_str()] = QString::fromStdString(value<std::string>(s->long_name().c_str()).value());
        }
    }

    return v;
}