// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "cdateedit.h"
#include "lunarcalendarwidget.h"
#include "lunarmanager.h"
#include "commondef.h"

#include <QCoreApplication>
#include <QLineEdit>
#include <QDebug>

CDateEdit::CDateEdit(QWidget *parent) : QDateEdit(parent)
{
    qCDebug(ClientLogger) << "Creating CDateEdit widget";
    connect(this, &QDateEdit::userDateChanged, this, &CDateEdit::slotDateEidtInfo);
    connect(lineEdit(), &QLineEdit::textChanged, this, &CDateEdit::slotRefreshLineEditTextFormat);
    connect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &CDateEdit::slotCursorPositionChanged);
    connect(lineEdit(), &QLineEdit::selectionChanged, this, &CDateEdit::slotSelectionChanged);
    connect(lineEdit(), &QLineEdit::editingFinished, this, [this]() {
        qCDebug(ClientLogger) << "Date edit finished, refreshing text format";
        //监听完成输入信号，触发文本改变事件，保证退出文本编辑的情况下依旧能刷新文本样式
        //当非手动输入时间时不会触发文本改变信号
        slotRefreshLineEditTextFormat(text());
    });
}

void CDateEdit::setDate(QDate date)
{
    qCDebug(ClientLogger) << "CDateEdit::setDate - Setting date to:" << date;
    QDateEdit::setDate(date);
    //只有在农历日程时，才需要获取农历信息
    QString dtFormat = m_showLunarCalendar ? m_format + getLunarName(date) : m_format;
    m_strCurrrentDate = date.toString(dtFormat);
    qCDebug(ClientLogger) << "Updated current date string:" << m_strCurrrentDate;
}

void CDateEdit::setDisplayFormat(QString format)
{
    qCDebug(ClientLogger) << "Setting display format to:" << format;
    this->m_format = format;
    //刷新时间显示信息
    slotDateEidtInfo(date());
}

QString CDateEdit::displayFormat()
{
    qCDebug(ClientLogger) << "CDateEdit::displayFormat - Returning format:" << m_format;
    return m_format;
}

void CDateEdit::setLunarCalendarStatus(bool status)
{
    qCDebug(ClientLogger) << "Setting lunar calendar status to:" << status;
    m_showLunarCalendar = status;
    //刷新时间显示信息
    slotDateEidtInfo(date());
    //更新日历显示类型
    updateCalendarWidget();
}

void CDateEdit::setLunarTextFormat(QTextCharFormat format)
{
    qCDebug(ClientLogger) << "CDateEdit::setLunarTextFormat - Setting lunar text format";
    m_lunarTextFormat = format;
    //刷新文本样式
    slotRefreshLineEditTextFormat(text());
}

QTextCharFormat CDateEdit::getsetLunarTextFormat()
{
    // qCDebug(ClientLogger) << "CDateEdit::getsetLunarTextFormat - Returning lunar text format";
    return m_lunarTextFormat;
}

void CDateEdit::setCalendarPopup(bool enable)
{
    qCDebug(ClientLogger) << "Setting calendar popup to:" << enable;
    QDateEdit::setCalendarPopup(enable);
    //更新日历显示类型
    updateCalendarWidget();
}

void CDateEdit::slotDateEidtInfo(const QDate &date)
{
    qCDebug(ClientLogger) << "CDateEdit::slotDateEidtInfo - Setting date edit info for date:" << date;
    QString format = m_format;

    if (m_showLunarCalendar) {
        qCDebug(ClientLogger) << "CDateEdit::slotDateEidtInfo - Showing lunar calendar";
        if (!showGongli()) {
            qCDebug(ClientLogger) << "Hiding Gregorian calendar due to space constraints";
            format = "yyyy/";
        }
        m_lunarName = getLunarName(date);
        format += m_lunarName;
        qCDebug(ClientLogger) << "Updated lunar calendar format:" << format << "lunar name:" << m_lunarName;
    }
    //当当前显示格式与应该显示格式一致时不再重新设置
    if (QDateEdit::displayFormat() == format) {
        qCDebug(ClientLogger) << "Display format unchanged, skipping update";
        return;
    }

    //记录刷新格式前的状态
    bool hasSelected = lineEdit()->hasSelectedText();   //是否选择状态
    int cPos = 0;
    QDateTimeEdit::Section section = QDateTimeEdit::NoSection;
    if (hasSelected) {
        section = currentSection();     //选择节
        qCDebug(ClientLogger) << "Preserving selection state, section:" << section;
    } else {
        cPos = lineEdit()->cursorPosition();    //光标所在位置
        qCDebug(ClientLogger) << "Preserving cursor position:" << cPos;
    }

    QDateEdit::setDisplayFormat(format);

    //恢复原状
    if (hasSelected) {
        qCDebug(ClientLogger) << "Restoring selection state, section:" << section;
        setSelectedSection(section);    //设置选中节
    } else {
        qCDebug(ClientLogger) << "Restoring cursor position:" << cPos;
        lineEdit()->setCursorPosition(cPos);    //设置光标位置
    }
    //刷新文本样式
    //当非手动输入时间时不会触发文本改变信号
    slotRefreshLineEditTextFormat(date.toString(format));
}

void CDateEdit::slotRefreshLineEditTextFormat(const QString &text)
{
    qCDebug(ClientLogger) << "CDateEdit::slotRefreshLineEditTextFormat - Refreshing line edit text format for text:" << text;
    QFont font = lineEdit()->font();
    QFontMetrics fm(font);
    int textWidth = fm.horizontalAdvance(text);
    int maxWidth = lineEdit()->width() - 25; //文本能正常显示的最大宽度
    if (textWidth > maxWidth) {
        setToolTip(text);
    } else {
        setToolTip("");
    }

    //不显示农历时无需处理
    if (!m_showLunarCalendar) {
        qCDebug(ClientLogger) << "CDateEdit::slotRefreshLineEditTextFormat - Not showing lunar calendar, returning";
        return;
    }

    QList<QTextLayout::FormatRange> formats;
    QTextLayout::FormatRange fr_tracker;

    fr_tracker.start = text.size() - m_lunarName.size();    //样式起始位置
    fr_tracker.length = m_lunarName.size();                 //样式长度
    fr_tracker.format = m_lunarTextFormat;                  //样式

    formats.append(fr_tracker);
    //更改农历文本样式
    setLineEditTextFormat(lineEdit(), formats);
}

void CDateEdit::slotCursorPositionChanged(int oldPos, int newPos)
{
    qCDebug(ClientLogger) << "CDateEdit::slotCursorPositionChanged - Cursor position changed from:" << oldPos << "to:" << newPos;
    //不显示农历时无需处理
    if (!m_showLunarCalendar) {
        qCDebug(ClientLogger) << "CDateEdit::slotCursorPositionChanged - Not showing lunar calendar, returning";
        return;
    }
    Q_UNUSED(oldPos);

    //光标最大位置不能超过时间长度不能覆盖农历信息
    int maxPos = text().length() - m_lunarName.length();
    bool hasSelected = lineEdit()->hasSelectedText();

    if (hasSelected) {
        int startPos = lineEdit()->selectionStart();
        int endPos = lineEdit()->selectionEnd();

        //新的光标位置与选择区域末尾位置相等则是向后选择，向前选择无需处理
        if (newPos == endPos) {
            newPos = newPos > maxPos ? maxPos : newPos;
            lineEdit()->setSelection(startPos, newPos - startPos); //重新设置选择区域
        }
    } else {
        //非选择情况当新光标位置大于最大位置时设置到最大位置处，重新设置选中节位最后一节
        if (newPos > maxPos) {
            setCurrentSectionIndex(sectionCount() - 1);
            lineEdit()->setCursorPosition(maxPos);
        }
    }
}

void CDateEdit::slotSelectionChanged()
{
    qCDebug(ClientLogger) << "CDateEdit::slotSelectionChanged - Selection changed";
    //不显示农历时无需处理
    if (!m_showLunarCalendar) {
        qCDebug(ClientLogger) << "CDateEdit::slotSelectionChanged - Not showing lunar calendar, returning";
        return;
    }
    //全选时重新设置为只选择时间不选择农历
    if (lineEdit()->hasSelectedText() && lineEdit()->selectionEnd() == text().length()) {
        int startPos = lineEdit()->selectionStart();
        lineEdit()->setSelection(startPos, text().length() - m_lunarName.length() - startPos);
    }
}

QString CDateEdit::getLunarName(const QDate &date)
{
    QString lunarName = gLunarManager->getHuangLiShortName(date);
    // qCDebug(ClientLogger) << "CDateEdit::getLunarName - Date:" << date << "Lunar name:" << lunarName;
    return lunarName;
}

void CDateEdit::setLineEditTextFormat(QLineEdit *lineEdit, const QList<QTextLayout::FormatRange> &formats)
{
    qCDebug(ClientLogger) << "CDateEdit::setLineEditTextFormat - Setting text format for line edit";
    if (!lineEdit) {
        qCDebug(ClientLogger) << "Line edit is null, returning";
        return;
    }
    QList<QInputMethodEvent::Attribute> attributes;

    for (const QTextLayout::FormatRange &fr : formats) {
        QInputMethodEvent::AttributeType type = QInputMethodEvent::TextFormat;

        int start = fr.start - lineEdit->cursorPosition();
        int length = fr.length;
        QVariant value = fr.format;

        attributes.append(QInputMethodEvent::Attribute(type, start, length, value));
    }

    QInputMethodEvent event(QString(), attributes);
    qCDebug(ClientLogger) << "Sending input method event with" << attributes.size() << "attributes";
    QCoreApplication::sendEvent(lineEdit, &event);
}

void CDateEdit::changeEvent(QEvent *e)
{
    // qCDebug(ClientLogger) << "CDateEdit::changeEvent - Change event detected";
    QDateEdit::changeEvent(e);
    if (e->type() == QEvent::FontChange && m_showLunarCalendar) {
        qCDebug(ClientLogger) << "CDateEdit::changeEvent - Font change detected, refreshing date info";
        slotDateEidtInfo(date());
    }
}

bool CDateEdit::showGongli()
{
    qCDebug(ClientLogger) << "CDateEdit::showGongli - Current date:" << m_strCurrrentDate;
    QString str = m_strCurrrentDate;
    QFontMetrics fontMetrice(lineEdit()->font());
    if (fontMetrice.horizontalAdvance(str) > lineEdit()->width() - 20) {
        qCDebug(ClientLogger) << "CDateEdit::showGongli - Current date width is greater than line edit width, returning false";
        return false;
    }
    qCDebug(ClientLogger) << "CDateEdit::showGongli - Current date width is less than line edit width, returning true";
    return true;
}

void CDateEdit::updateCalendarWidget()
{
    qCDebug(ClientLogger) << "CDateEdit::updateCalendarWidget - Calendar popup:" << calendarPopup() 
                         << "Show lunar calendar:" << m_showLunarCalendar;
    if (calendarPopup()) {
        //setCalendarWidget:
        //The editor does not automatically take ownership of the calendar widget.
        if (m_showLunarCalendar) {
            qCDebug(ClientLogger) << "Creating and setting lunar calendar widget";
            setCalendarWidget(new LunarCalendarWidget(this));
        } else {
            qCDebug(ClientLogger) << "Creating and setting standard calendar widget";
            setCalendarWidget(new QCalendarWidget(this));
        }
    }
}

void CDateEdit::setEditCursorPos(int pos)
{
    qCDebug(ClientLogger) << "CDateEdit::setEditCursorPos - Setting cursor position to:" << pos;
    QLineEdit *edit = lineEdit();
    if (nullptr != edit) {
        qCDebug(ClientLogger) << "CDateEdit::setEditCursorPos - Line edit is not null, setting cursor position to:" << pos;
        edit->setCursorPosition(pos);
    }
}

