#include "pagelistitem.h"
#include "cfg.h"
#include "tools.h"
#include "base/ffutil.h"
#include "program/wplanlist.h"
#include "base/lodateselector.h"
#include "program/ebase.h"
#include "program/etext.h"
#include "program/ephoto.h"
#include "program/evideo.h"
#include "program/eaudio.h"
#include "program/egif.h"
#include "program/edclock.h"
#include "program/eaclock.h"
#include "program/eenviron.h"
#include "program/eweb.h"
#include "program/etimer.h"
#include "program/emultiwin.h"
#include "globaldefine.h"
#include <QMessageBox>
#include <QJsonArray>
#include <QDir>
#include <QBoxLayout>
#include <QSpinBox>
#include <QLineEdit>
#include <QDateEdit>

class PageScene : public QGraphicsScene {
public:
    PageScene(qreal x, qreal y, qreal width, qreal height, QObject *parent = nullptr) : QGraphicsScene(x, y, width, height, parent) {};
    void drawBackground(QPainter *painter, const QRectF &rect) {
        QGraphicsScene::drawBackground(painter, rect);
        painter->fillRect(sceneRect(), Qt::black);
    }
};

PageListItem::PageListItem(const QJsonObject &attr, const QString &pageDir) : mAttr(attr), mPageDir(pageDir) {
    setSizeHint(QSize(0,80));
    mScene = new PageScene(0, 0, gProgItem->mWidth, gProgItem->mHeight, this);
    auto elements = mAttr["elements"].toArray();
    foreach(auto ele, elements) {
        QString type = ele["elementType"].toString();
        EBase *element = 0;
        if(type=="Text") element = new EText(ele.toObject());
        else if(type=="Photo") element = EPhoto::create(ele.toObject(), this);
        else if(type=="Gif") element = EGif::create(ele.toObject(), this);
        else if(type=="Movie") element = EVideo::create(ele.toObject(), this);
        else if(type=="Audio") element = EAudio::create(ele.toObject(), this);
        else if(type=="DClock") element = new EDClock(ele.toObject());
        else if(type=="AClock") element = new EAClock(ele.toObject());
        else if(type=="Temp") element = new EEnviron(ele.toObject());
        else if(type=="Web") element = new EWeb(ele.toObject());
        else if(type=="Timer") element = new ETimer(ele.toObject());
        else if(type=="Window") element = new EMultiWin(ele.toObject(), this);
        if(element) mScene->addItem(element);
    }
}

//更新页属性参数到page.json
void PageListItem::updateJson() {
    if(mAttrWgt==0) return; //没有点开该页面进行编辑
    QJsonArray elements;
    auto items = mScene->items();
    foreach(auto item, items) {
        auto element = static_cast<EBase*>(item);
        if(element->mMultiWin == nullptr) elements.append(element->attrJson());
    }
    mAttr.insert("elements", elements);

    QJsonArray audios;
    auto cnt = mAudiosList->count();
    for(int i=0; i<cnt; i++) {
        auto info = mAudiosList->item(i)->data(Qt::UserRole).value<AudioInfo>();
        audios.append(QJsonObject{
            {"dir", info.dir},
            {"name", info.name},
            {"dur", info.dur},
            {"vol", info.vol}
        });
    }
    mAttr.insert("audios", audios);
}
bool PageListItem::saveFiles() {
    mPageDir = gProgItem->mProgDir + "/" + mAttr["name"].toString();
    QDir pageQDir(mPageDir);
    if(! pageQDir.exists() && ! pageQDir.mkpath(".")) return false;

    QJsonArray elements;
    auto items = mScene->items();
    foreach(auto item, items) {
        auto element = static_cast<EBase*>(item);
        if(element->mMultiWin == nullptr && element->save(mPageDir)) elements.append(element->attrJson());
    }
    mAttr.insert("elements", elements);
    if(mAttrWgt!=0) {
        QJsonArray audios;
        auto cnt = mAudiosList->count();
        for(int i=0; i<cnt; i++) {
            auto info = mAudiosList->item(i)->data(Qt::UserRole).value<AudioInfo>();
            QString oldFile = info.dir + PAGEDEL_SUFFIX + "/" + info.name;
            if(QFileInfo::exists(oldFile)) ;
            else if(QFileInfo::exists(oldFile = info.dir + "/" + info.name)) ;
            else continue;
            QFile::copy(oldFile, mPageDir + "/" + info.name);
            info.dir = mPageDir;
            audios.append(QJsonObject{
                {"dir", info.dir},
                {"name", info.name},
                {"dur", info.dur},
                {"vol", info.vol}
            });
        }
        mAttr.insert("audios", audios);
    }

    QFile file(mPageDir + "/page.json");
    if(! file.open(QIODevice::WriteOnly)) {
        QMessageBox::critical(gMainWin, "Write Error", mPageDir + "/page.json "+file.errorString());
        return false;
    }
    file.write(QJsonDocument(mAttr).toJson());
    file.close();
    return true;
}

QWidget *PageListItem::itemWgt() {
    auto wgtPage = new QWidget();
    auto hBox = new QHBoxLayout(wgtPage);
    mGraView = new QGraphicsView();
    mGraView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    mGraView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    mGraView->setEnabled(false);
    mGraView->setFrameShape(QFrame::NoFrame);
    mGraView->setFixedSize(120, 60);
    mGraView->setStyleSheet("QGraphicsView{background-color:transparent;}");
    mGraView->setScene(mScene);
    qreal scale = qMin(mGraView->width() / mScene->width(), mGraView->height() / mScene->height());
    mGraView->scale(scale, scale);
    hBox->addWidget(mGraView);

    fdPlayTimes = new QLabel(QString::number(mAttr["repeat"].toInt()));
    hBox->addWidget(fdPlayTimes);

    hBox->addWidget(new QLabel(tr("times")));
    hBox->addStretch();
    return wgtPage;
}

QWidget *PageListItem::attrWgt() {
    if(mAttrWgt!=0) return mAttrWgt;
    mAttrWgt = new QWidget();
    mAttrWgt->setStyleSheet(R"rrr(
QPushButton {
    padding-left: 4px;
    padding-right: 4px;
    padding-top: 2px;
    padding-bottom: 2px;
    border-radius: 4px;
}
QPushButton:hover {
    background-color: #dddddd;
}

QPushButton#bnAddPlan {
    image: url(:/res/program/AddPlan.png);
    width: 24;
    height: 24;
}
QPushButton#bnClearPlan {
    image: url(:/res/program/Clean.png);
    width: 24;
    height: 24;
}
QPushButton#bnDel {
    image: url(:/res/program/Delete.png);
    width: 18;
    height: 18;
}
QPushButton#bnAddPlan:pressed,
QPushButton#bnClearPlan:pressed,
QPushButton#bnDel:pressed {
    margin-top: 1px;
    margin-left: 1px;
    margin-bottom: -1px;
    margin-right: -1px;
}

QPushButton[ssName="weeklySelector"] {
    border: 1px solid #6A838F;
    width: 24;
    height: 24;
}
QPushButton[ssName="weeklySelector"]:checked {
    background-color: #0099cc;
}
)rrr");
    auto vBox = new QVBoxLayout(mAttrWgt);
    vBox->setContentsMargins(6, 0, 6, 0);
    vBox->setSpacing(4);

    auto hBox = new QHBoxLayout();
    auto lb1 = new QLabel(tr("Page name"));
    lb1->setMinimumWidth(80);
    hBox->addWidget(lb1);

    auto fdPageName = new QLineEdit(mAttr["name"].toString());
    connect(fdPageName, &QLineEdit::textEdited, this, [this, fdPageName](const QString &text) {
        bool isDupli = false;
        auto listWgt = listWidget();
        if(nullptr != listWgt) {
            int n = listWgt->count();
            for(int i=0; i<n; i++) {
                auto item = static_cast<PageListItem*>(listWgt->item(i));
                if(text == item->mAttr["name"].toString()) {
                    isDupli = true;
                    break;
                }
            }
        }
        if(isDupli) {
            QString newName = tr("New") + QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz");
            mAttr["name"] = newName;
            fdPageName->setText(newName);
        } else mAttr["name"] = text;
    });
    hBox->addWidget(fdPageName);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    lb1 = new QLabel(tr("Play times"));
    lb1->setMinimumWidth(80);
    hBox->addWidget(lb1);

    auto fdPlayTimes = new QSpinBox();
    fdPlayTimes->setRange(1, 9999);
    fdPlayTimes->setValue(mAttr["repeat"].toInt());
    connect(fdPlayTimes, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        mAttr["repeat"] = value;
        this->fdPlayTimes->setText(QString::number(value));
    });
    hBox->addWidget(fdPlayTimes);
    hBox->addSpacing(20);

    auto fdLoop = new QCheckBox(tr("Sources Repeat"));
    fdLoop->setChecked(mAttr["loop"].toBool());
    connect(fdLoop, &QCheckBox::toggled, this, [this](bool checked) {
        mAttr["loop"] = checked;
    });
    hBox->addWidget(fdLoop);

    hBox->addStretch();

    vBox->addLayout(hBox);

    auto line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    vBox->addWidget(line);

    hBox = new QHBoxLayout();
    auto lb = new QLabel();
    lb->setPixmap(QPixmap(":/res/program/Audio.png").scaledToHeight(24, Qt::SmoothTransformation));
    hBox->addWidget(lb);
    hBox->addWidget(new QLabel(tr("Audios")));
    hBox->addStretch();

    hBox->addWidget(new QLabel(tr("Total Dur")));
    auto fdTtlDur = new QLabel("0");
    hBox->addWidget(fdTtlDur);
    hBox->addWidget(new QLabel(tr("s")));
    hBox->addStretch();

    auto btnAdd = new QPushButton();
    btnAdd->setIcon(QIcon(":/res/program/Add.png"));
    btnAdd->setProperty("style","multiTool");

    mAudiosList = new QListWidget();
    connect(btnAdd, &QPushButton::clicked, this, [this, fdTtlDur] {
        auto files = QFileDialog::getOpenFileNames(gMainWin, tr("Select File"), gFileHome, EAudio::filters());
        int durs = fdTtlDur->text().toInt();
        for(int i=0; i<files.count(); i++) {
            int64_t dur;
            QString err = audioInfo(files[i].toUtf8(), &dur);
            if(! err.isEmpty()) {
                QMessageBox::critical(gMainWin, "Audio Error", err+"\n"+files[i]);
                continue;
            }
            QFileInfo fInfo(files[i]);
            AudioInfo info{fInfo.absolutePath(), fInfo.fileName(), (int)(dur/1000000)};
            auto item = new QListWidgetItem(QIcon(":/res/program/Audio.png"), info.name);
            item->setData(Qt::UserRole, QVariant::fromValue(info));
            mAudiosList->addItem(item);
            if(i == files.count()-1) {
                mAudiosList->setCurrentItem(item);
                gFileHome = fInfo.absolutePath();
            }
            durs += info.dur;
            mAudiosList->addItem(item);
        }
        fdTtlDur->setText(QString::number(durs));
    });
    hBox->addWidget(btnAdd);

    auto btnDel = new QPushButton();
    btnDel->setIcon(QIcon(":/res/program/Delete.png"));
    btnDel->setProperty("style","multiTool");
    connect(btnDel, &QPushButton::clicked, this, [this, fdTtlDur] {
        auto row = mAudiosList->currentRow();
        if(row < 0) return;
        int durs = fdTtlDur->text().toInt();
        auto item = mAudiosList->takeItem(row);
        auto info = static_cast<AudioInfo>(item->data(Qt::UserRole).value<AudioInfo>());
        durs -= info.dur;
        delete item;
        fdTtlDur->setText(QString::number(durs));
    });
    hBox->addWidget(btnDel);

    auto btnGoUp = new QPushButton();
    btnGoUp->setIcon(QIcon(":/res/program/GoUp.png"));
    btnGoUp->setProperty("style","multiTool");
    connect(btnGoUp, &QPushButton::clicked, this, [this] {
        int row = mAudiosList->currentRow();
        if(row < 1) return;
        mAudiosList->insertItem(row-1, mAudiosList->takeItem(row));
        mAudiosList->setCurrentRow(row-1);
    });
    hBox->addWidget(btnGoUp);

    auto btnGoDown = new QPushButton();
    btnGoDown->setIcon(QIcon(":/res/program/GoDown.png"));
    btnGoDown->setProperty("style","multiTool");
    connect(btnGoDown, &QPushButton::clicked, this, [this] {
        int row = mAudiosList->currentRow();
        if(row < 0 || row > mAudiosList->count() - 2) return;
        mAudiosList->insertItem(row+1, mAudiosList->takeItem(row));
        mAudiosList->setCurrentRow(row+1);
    });
    hBox->addWidget(btnGoDown);

    vBox->addLayout(hBox);

    mAudiosList->setMinimumHeight(120);
    mAudiosList->setIconSize(QSize(20, 20));
    vBox->addWidget(mAudiosList, 1);

    auto audios = mAttr["audios"].toArray();
    int durs = 0;
    foreach(auto audio, audios) {
        AudioInfo info{audio["dir"].toString(), audio["name"].toString(), audio["dur"].toInt(), audio["vol"].toInt()};
        if(info.dir.isEmpty() || info.name.isEmpty() || info.dur==0) continue;
        auto item = new QListWidgetItem(QIcon(":/res/program/Audio.png"), info.name);
        item->setData(Qt::UserRole, QVariant::fromValue(info));
        durs += info.dur;
        mAudiosList->addItem(item);
    }
    fdTtlDur->setText(QString::number(durs));

    auto wgtAudioInfo = new QWidget();
    wgtAudioInfo->hide();
    hBox = new QHBoxLayout(wgtAudioInfo);
    hBox->setContentsMargins(0,0,0,0);
    hBox->setSpacing(2);

    hBox->addWidget(new QLabel(tr("Duration")));
    hBox->addSpacing(4);

    auto fdAudioDur = new QLabel("0");
    hBox->addWidget(fdAudioDur);
    hBox->addWidget(new QLabel(tr("s")));

    hBox->addStretch();
    hBox->addWidget(new QLabel(tr("Vol")));

    auto fdVol = new QSlider(Qt::Horizontal);
    fdVol->setMaximum(100);
    fdVol->setMinimumWidth(120);
    hBox->addWidget(fdVol);

    auto fdAudioVol = new QLabel("0");
    fdAudioVol->setAlignment(Qt::AlignRight);
    fdAudioVol->setFixedWidth(38);
    hBox->addWidget(fdAudioVol);

    vBox->addWidget(wgtAudioInfo);

    connect(fdVol, &QSlider::valueChanged, this, [this, fdAudioVol](int value) {
        fdAudioVol->setText(QString::number(value)+"%");
        auto item = mAudiosList->currentItem();
        if(item==nullptr) return;
        auto info = static_cast<AudioInfo>(item->data(Qt::UserRole).value<AudioInfo>());
        info.vol = value;
        item->setData(Qt::UserRole, QVariant::fromValue(info));
    });
    connect(mAudiosList, &QListWidget::currentItemChanged, this, [fdAudioDur, wgtAudioInfo, fdVol, fdAudioVol](QListWidgetItem *current, QListWidgetItem *) {
        if(current==nullptr) {
            wgtAudioInfo->hide();
            return;
        }
        wgtAudioInfo->show();
        auto info = static_cast<AudioInfo>(current->data(Qt::UserRole).value<AudioInfo>());
        fdAudioDur->setText(QString::number(info.dur));
        fdVol->setValue(info.vol);
        fdAudioVol->setText(QString::number(info.vol)+"%");
    });

    line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    vBox->addWidget(line);

    QJsonValue validDate = mAttr["validDate"];

    auto wValidDate = new QCheckBox(tr("Valid Date"));
    bool isDateValid = validDate["isValid"].toBool();
    wValidDate->setChecked(isDateValid);
    vBox->addWidget(wValidDate);

    hBox = new QHBoxLayout();

    auto fdStart = new QDateEdit();
    fdStart->setDisplayFormat("yyyy-MM-dd");
    fdStart->setEnabled(isDateValid);
    fdStart->setDate(QDate::fromString(validDate["start"].toString(), "yyyy-MM-dd"));
    hBox->addWidget(fdStart);

    auto bnDateStart = new LoDateSelector();
    bnDateStart->setEnabled(isDateValid);
    connect(bnDateStart, &LoDateSelector::sDateSelected, fdStart, &QDateEdit::setDate);
    hBox->addWidget(bnDateStart);

    hBox->addWidget(new QLabel("~"));

    auto fdEnd = new QDateEdit();
    fdEnd->setDisplayFormat("yyyy-MM-dd");
    fdEnd->setEnabled(isDateValid);
    fdEnd->setDate(QDate::fromString(validDate["end"].toString(), "yyyy-MM-dd"));
    connect(fdStart, &QDateEdit::dateChanged, this, [this, wValidDate, fdStart, fdEnd](const QDate &date) {
        auto end = fdEnd->date();
        if(! date.isValid() || date > end) {
            QMessageBox::warning(gMainWin, tr("Warning"), tr("Start Time can't be later than End Time"));
            fdStart->setDate(end);
        }
        mAttr["validDate"] = QJsonObject{
            {"isValid", wValidDate->isChecked()},
            {"start", fdStart->date().toString("yyyy-MM-dd")},
            {"end", end.toString("yyyy-MM-dd")}
        };
    });
    connect(fdEnd, &QDateEdit::dateChanged, this, [this, wValidDate, fdStart, fdEnd](const QDate &date) {
        QDate start = fdStart->date();
        if(! date.isValid() || start > date) {
            QMessageBox::warning(gMainWin, tr("Warning"), tr("End Time can't be earlier than Start Time"));
            fdEnd->setDate(start);
        }
        mAttr["validDate"] = QJsonObject{
            {"isValid", wValidDate->isChecked()},
            {"start", start.toString("yyyy-MM-dd")},
            {"end", fdEnd->date().toString("yyyy-MM-dd")}
        };
    });
    hBox->addWidget(fdEnd);

    auto bnDateEnd = new LoDateSelector();
    bnDateEnd->setEnabled(isDateValid);
    connect(bnDateEnd, &LoDateSelector::sDateSelected, fdEnd, &QDateEdit::setDate);
    hBox->addWidget(bnDateEnd);

    hBox->addStretch();

    connect(wValidDate, &QCheckBox::toggled, this, [this, fdStart, fdEnd, bnDateStart, bnDateEnd](bool checked) {
        fdStart->setEnabled(checked);
        fdEnd->setEnabled(checked);
        bnDateStart->setEnabled(checked);
        bnDateEnd->setEnabled(checked);
        mAttr["validDate"] = QJsonObject{
            {"isValid", checked},
            {"start", fdStart->date().toString("yyyy-MM-dd")},
            {"end", fdEnd->date().toString("yyyy-MM-dd")}
        };
    });

    vBox->addLayout(hBox);

    line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    vBox->addWidget(line);

    hBox = new QHBoxLayout();
    hBox->setSpacing(12);
    hBox->addWidget(new QLabel(tr("Plan")));

    hBox->addStretch();

    auto bnAddPlan = new QPushButton();
    bnAddPlan->setObjectName("bnAddPlan");
    hBox->addWidget(bnAddPlan);

    auto bnClearPlan = new QPushButton();
    bnClearPlan->setObjectName("bnClearPlan");
    hBox->addWidget(bnClearPlan);

    vBox->addLayout(hBox);

    auto wPlans = new wPlanList();
    wPlans->setStyleSheet(R"rrr(
QListWidget::item {
    height: 100;
    border-top: 1px solid #6A838F;
    margin-right: 9px;
})rrr");

    wPlans->onRestorePlan(mAttr["plans"].toArray());
    connect(bnAddPlan, &QPushButton::clicked, wPlans, &wPlanList::onAddPlan);
    connect(bnClearPlan, &QPushButton::clicked, wPlans, &wPlanList::clear);
    connect(wPlans, &QListWidget::itemChanged, this, [this, wPlans] {
        mAttr["plans"] = wPlans->plansJson();
    });
    vBox->addWidget(wPlans, 2);
    return mAttrWgt;
}