#include "AppManagerMainWidget.h"

#include <QVBoxLayout>
#include <QComboBox>

#include "Ukui4CustomControl.h"

AppManagerMainWidget::AppManagerMainWidget(QWidget* parent)
    : KWidget(parent)
{
    initUi();
    initSlots();
}

QList<ClientDeviceInfo> getAvailablePortList(const NodeType& type)
{
    QList<ClientDeviceInfo> list;

    QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
                                                                  AUDIO_OBJECT_PATH,
                                                                  AUDIO_INTERFACE,
                                                                  "getAvailablePortList",
                                                                  EnumToInt(type));

    if (reply.arguments().isEmpty()) {
        qDebug() << "返回参数为空";
        return {};
    }

    const QDBusArgument& dbusArgs = reply.arguments().at(0).value<QDBusArgument>();

    dbusArgs.beginArray();
    while (!dbusArgs.atEnd()) {
        ClientDeviceInfo info;
        dbusArgs >> info;
        list.push_back(info);
    }
    dbusArgs.endArray();

    return list;
}

void AppManagerMainWidget::initUi()
{
    setIcon(QIcon::fromTheme("ukui-control-center"));
    setWidgetName(tr("App Sound Control"));
    setWindowFlags(Qt::Dialog);
    setWindowModality(Qt::WindowModality::WindowModal);
    setContentsMargins(0, 0, 0, 0);
    setFixedSize(760, 520);

    m_pNavigationBar = new kdk::KNavigationBar(this);

    for (const auto& [k, v] : m_itemMap) {
        m_pNavigationBar->addItem(v);
    }

    m_pNavigationBar->setFixedSize(200, 478);
    m_pNavigationBar->setContentsMargins(0, 0, 0, 0);

    auto vLayout = new QVBoxLayout(this);
    vLayout->setContentsMargins(6, 20, 0, 0);
    vLayout->setSpacing(0);
    vLayout->addWidget(m_pNavigationBar);
    sideBar()->setLayout(vLayout);

    // 创建QStackedWidget用于管理不同的界面
    m_pStackedWidget = new QStackedWidget(this);
    m_pStackedWidget->setContentsMargins(0, 0, 0, 0);
    m_pStackedWidget->setFixedSize(560, 478);

    for (const auto& [k, v] : m_appWidgetMap) {
        m_pStackedWidget->addWidget(v);
    }

    // 添加右侧设备窗口布局
    auto vLayout2 = new QVBoxLayout;
    vLayout2->setContentsMargins(0, 20, 0, 0);
    vLayout2->setSpacing(0);
    vLayout2->addWidget(m_pStackedWidget);
    baseBar()->setLayout(vLayout2);

    setLayoutType(kdk::HorizontalType);
}

void AppManagerMainWidget::initSlots()
{
    connect(m_pNavigationBar->listview(), &QListView::clicked, this, [=](const QModelIndex &index){
        auto idx = index.row();
        m_pStackedWidget->setCurrentIndex(idx);
    });
}

void AppManagerMainWidget::addItem(int idx, int value, bool muted, const QString& icon, const QString& desc, const QList<ClientDeviceInfo>& outputList, const QList<ClientDeviceInfo>& inputList)
{
    //start
    if (desc.compare("sound-theme-player") == 0) {
        return;
    }
    //end

    StreamDirection direction = StreamDirection::STREAM_DIRECTION_OUTPUT;
    if (idx == -1)
        direction = StreamDirection::STREAM_DIRECTION_BOTH;

    auto wid = new AppManagerItemWidget(idx, new AutoOmitLabel(desc), icon, direction, this);
    auto item = new QStandardItem(QIcon::fromTheme(icon), desc);

    wid->setMuted(VolumeSliderType::VOLUME_SLIDER_SINKINPUT, muted);
    wid->setValue(VolumeSliderType::VOLUME_SLIDER_SINKINPUT, value);

    qDebug() << QString("add %1 to app widget, index: %2, icon: %3.").arg(desc).arg(idx).arg(icon);

    // 设置项的样式
    QString itemStyle = "QStandardItem { min-width: 176px; max-width: 176px; min-height: 36px; max-height: 36px; }";
    item->setData(itemStyle, Qt::UserRole);

    m_pStackedWidget->addWidget(wid);
    m_pNavigationBar->addItem(item);
    m_itemMap.emplace(idx, item);
    m_appWidgetMap.emplace(idx, wid);

    for (const auto dev : outputList) {
        addPortToAppItem(idx, NodeType::OUTPUT, QString(dev.portLabel + " (" + dev.cardDesc + ")"),
                         QVariant(std::initializer_list<QString> {dev.cardName, dev.portName}));
    }

    for (const auto dev : inputList) {
        addPortToAppItem(idx, NodeType::INPUT, QString(dev.portLabel + " (" + dev.cardDesc + ")"),
                         QVariant(std::initializer_list<QString> {dev.cardName, dev.portName}));
    }

    auto s = static_cast<QSlider*>(wid->getSliderItem()->getSlider()->getWidget());
    auto btn = wid->getSliderItem()->getMuteBtn();

    connect(wid, &AppManagerItemWidget::closeWindowSignals, this, [this]() {
        Q_EMIT closeWindowSignals();
    });

    if (s) {
        connect(s, &QSlider::valueChanged, this, [idx, icon, this](int val) {
            Q_EMIT valueChangedSignals(idx, val);
            //start
            qDebug() << "AppManagerMainWidget valueChanged icon:" << icon << "val:" << val;
            if ((icon.compare(QString("kylin-music")) == 0)
                || (icon.compare(QString("kylin-video")) == 0)) {
                QDBusMessage msg = QDBusMessage::createSignal(QString("/"), QString("org.ukui.media"), QString("sinkVolumeChanged"));
                msg << icon << val << false;
                QDBusConnection::sessionBus().send(msg);
            }
            //end
        });
    }

    if (btn) {
        connect(btn, &QPushButton::clicked, this, [idx, this]() {
            Q_EMIT muteChangedSignals(idx);
        });
    }

    auto selectComboxList = wid->getSelectComboxItems();
    for (const auto& box : selectComboxList) {

        auto combox = static_cast<QComboBox*>(box.second->getSelectBox()->getWidget());
        connect(combox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [idx, box, desc, this](int) {
            auto data = box.second->getSelectBox()->currentData().toStringList();
            if (data.size() < 2) {
                qWarning() << QString("Ivalid combox data.");
                return;
            }

            qDebug() << QString("%1 application change device to card: %2, port: %3").arg(desc).arg(data.at(0)).arg(data.at(1));
            Q_EMIT currentIndexChangedSignals(idx, data.at(0), data.at(1));
        });
    }
}

void AppManagerMainWidget::removeItem(int idx)
{
    auto it = m_appWidgetMap.find(idx);

    if (it != m_appWidgetMap.end()) {
        m_pStackedWidget->removeWidget(it->second);
        m_appWidgetMap.erase(it);
    }
    else
        qWarning() << QString("Can not found %1 stream in app manager widget, remove failed.").arg(idx);

    auto at = m_itemMap.find(idx);
    if (at != m_itemMap.end()) {
        m_pNavigationBar->model()->removeRow(at->second->row());
        m_itemMap.erase(at);
    }
    else
        qWarning() << QString("Can not found %1 stream in app manager widget, remove failed.").arg(idx);
}

void AppManagerMainWidget::setValue(int idx, int value)
{
    auto it = m_appWidgetMap.find(idx);
    if (it != m_appWidgetMap.end()) {
        it->second->getSliderItem()->setValue(value);
    }
    else {
        qWarning() << QString("Does not exit %1 stream, set value failed.").arg(idx);
    }
}

void AppManagerMainWidget::setMute(int idx, bool mute)
{
    auto it = m_appWidgetMap.find(idx);
    if (it != m_appWidgetMap.end()) {
        it->second->getSliderItem()->setMute(mute);
    }
    else {
        qWarning() << QString("Does not exit %1 stream, set mute failed.").arg(idx);
    }
}

void AppManagerMainWidget::setCurrentItem(int index)
{
    auto model = m_pNavigationBar->model();
    m_pNavigationBar->listview()->setCurrentIndex(model->item(index, 0)->index());
}

void AppManagerMainWidget::setCurrentIndex(int appIndex, const NodeType& type, int index)
{
    auto it = m_appWidgetMap.find(appIndex);
    if (it != m_appWidgetMap.end()) {
        it->second->setCurrentIndex(type, index);
    }
    else {
        qWarning() << QString("Does not exit %1 stream, set current index failed.").arg(appIndex);
    }
}

void AppManagerMainWidget::addPortToAppItem(int idx, const NodeType& type, const QString& text, const QVariant& data)
{
    auto it = m_appWidgetMap.find(idx);

    if (it != m_appWidgetMap.end()) {
        it->second->insertItem(type, text, data);
    }
    else {
        qWarning() << QString("Does not exit %1 stream, add port failed.").arg(idx);
    }
}

void AppManagerMainWidget::removeProtFromAppItem(int streamIdx, const NodeType& type, int cbxIndex)
{
    auto it = m_appWidgetMap.find(streamIdx);

    if (it != m_appWidgetMap.end()) {
        it->second->removeItem(type, cbxIndex);
    }
    else {
        qWarning() << QString("Does not exit %1 stream, remove port failed.").arg(streamIdx);
    }
}

std::unordered_map<uint32_t, AppManagerItemWidget*> AppManagerMainWidget::getAppItems() const
{
    return m_appWidgetMap;
}

AppManagerItemWidget* AppManagerMainWidget::getAppWidgetByIndex(int idx)
{
    auto it = m_appWidgetMap.find(idx);
    if (it != m_appWidgetMap.end()) {
        return m_appWidgetMap[idx];
    }

    return {};
}
