#include "calculatordesigner.h"

#include <QPushButton>

#include "expressionevaluator.h"
#include "ui_widget.h"

namespace {
bool isOperatorChar(QChar ch) {
    return ch == QLatin1Char('+') || ch == QLatin1Char('-') ||
           ch == QLatin1Char('*') || ch == QLatin1Char('/');
}

bool isDigitOrDotChar(QChar ch) {
    return ch.isDigit() || ch == QLatin1Char('.');
}
}  // namespace

CalculatorDesigner::CalculatorDesigner(QWidget* parent)
    : QWidget(parent), ui(new Ui::CalculatorForm) {
    ui->setupUi(this);   // 表单里的控件树 + QGridLayout 全部由 Designer XML 建好

    connect(ui->btn0, &QPushButton::clicked, this, [this] { onDigit(0); });
    connect(ui->btn1, &QPushButton::clicked, this, [this] { onDigit(1); });
    connect(ui->btn2, &QPushButton::clicked, this, [this] { onDigit(2); });
    connect(ui->btn3, &QPushButton::clicked, this, [this] { onDigit(3); });
    connect(ui->btn4, &QPushButton::clicked, this, [this] { onDigit(4); });
    connect(ui->btn5, &QPushButton::clicked, this, [this] { onDigit(5); });
    connect(ui->btn6, &QPushButton::clicked, this, [this] { onDigit(6); });
    connect(ui->btn7, &QPushButton::clicked, this, [this] { onDigit(7); });
    connect(ui->btn8, &QPushButton::clicked, this, [this] { onDigit(8); });
    connect(ui->btn9, &QPushButton::clicked, this, [this] { onDigit(9); });
    connect(ui->btnDot, &QPushButton::clicked, this, [this] { onDot(); });

    connect(ui->btnPlus, &QPushButton::clicked, this, [this] { onOperator(QLatin1Char('+')); });
    connect(ui->btnMinus, &QPushButton::clicked, this, [this] { onOperator(QLatin1Char('-')); });
    connect(ui->btnMul, &QPushButton::clicked, this, [this] { onOperator(QLatin1Char('*')); });
    connect(ui->btnDiv, &QPushButton::clicked, this, [this] { onOperator(QLatin1Char('/')); });

    connect(ui->btnLeftParen, &QPushButton::clicked, this, &CalculatorDesigner::onLeftParen);
    connect(ui->btnRightParen, &QPushButton::clicked, this, &CalculatorDesigner::onRightParen);

    connect(ui->btnEquals, &QPushButton::clicked, this, &CalculatorDesigner::onEquals);
    connect(ui->btnClear, &QPushButton::clicked, this, &CalculatorDesigner::onClear);
    connect(ui->btnBackspace, &QPushButton::clicked, this, &CalculatorDesigner::onBackspace);

    onClear();
}

CalculatorDesigner::~CalculatorDesigner() { delete ui; }

void CalculatorDesigner::onDigit(int digit) {
    if (m_error) onClear();
    if (m_resultShown) {
        m_expression.clear();
        m_openParenCount = 0;
        m_resultShown = false;
    }

    const QString token = currentOperandToken();
    if (token == QStringLiteral("0")) {
        m_expression.chop(1);  // 用新数字替换孤立的前导 0，避免出现 "007"
    } else if (currentOperandDigitCount() >= kMaxOperandLength) {
        return;  // 达到单个运算数的长度上限，忽略后续数字
    }
    if (m_expression.size() >= kMaxExpressionLength) return;

    m_expression.append(QString::number(digit));
    refreshDisplays();
}

void CalculatorDesigner::onDot() {
    if (m_error) onClear();
    if (m_resultShown) {
        m_expression.clear();
        m_openParenCount = 0;
        m_resultShown = false;
    }

    const QString token = currentOperandToken();
    if (token.contains(QLatin1Char('.'))) return;  // 当前运算数已有小数点

    const int appended = token.isEmpty() ? 2 : 1;  // 空token时需要补一个前导 0
    if (m_expression.size() + appended > kMaxExpressionLength) return;

    if (token.isEmpty()) m_expression.append(QLatin1Char('0'));
    m_expression.append(QLatin1Char('.'));
    refreshDisplays();
}

void CalculatorDesigner::onOperator(QChar op) {
    if (m_error) return;
    if (m_resultShown) {
        m_expression = m_lastResultText;
        m_resultShown = false;
    }

    if (m_expression.isEmpty()) {
        if (op != QLatin1Char('-')) return;  // 表达式开头只允许负号（单目负号）
    } else {
        const QChar last = m_expression.at(m_expression.size() - 1);
        if (last == QLatin1Char('(')) {
            if (op != QLatin1Char('-')) return;  // 左括号后只允许负号
        } else if (isOperatorChar(last)) {
            m_expression.chop(1);  // 连续按运算符时，用新的运算符替换上一个
        }
    }

    if (m_expression.size() >= kMaxExpressionLength) return;
    m_expression.append(op);
    refreshDisplays();
}

void CalculatorDesigner::onLeftParen() {
    if (m_error) onClear();
    if (m_resultShown) {
        m_expression.clear();
        m_openParenCount = 0;
        m_resultShown = false;
    }

    if (!m_expression.isEmpty()) {
        const QChar last = m_expression.at(m_expression.size() - 1);
        if (!isOperatorChar(last) && last != QLatin1Char('(')) {
            return;  // 数字或右括号后不支持隐式乘法，忽略
        }
    }
    if (m_expression.size() >= kMaxExpressionLength) return;

    m_expression.append(QLatin1Char('('));
    ++m_openParenCount;
    refreshDisplays();
}

void CalculatorDesigner::onRightParen() {
    if (m_error) return;
    if (m_resultShown) return;
    if (m_openParenCount <= 0 || m_expression.isEmpty()) return;

    const QChar last = m_expression.at(m_expression.size() - 1);
    if (isOperatorChar(last) || last == QLatin1Char('(')) return;  // 括号内需要完整子表达式
    if (m_expression.size() >= kMaxExpressionLength) return;

    m_expression.append(QLatin1Char(')'));
    --m_openParenCount;
    refreshDisplays();
}

void CalculatorDesigner::onEquals() {
    if (m_error) return;
    if (m_expression.isEmpty()) return;

    QString toEvaluate = m_expression;
    for (int i = 0; i < m_openParenCount; ++i) toEvaluate.append(QLatin1Char(')'));  // 自动补全未闭合括号

    const ExpressionEvaluator::Result result = ExpressionEvaluator::evaluate(toEvaluate);
    if (!result.ok) {
        showError();
        return;
    }

    const QString resultText = QString::number(result.value, 'g', ExpressionEvaluator::kResultPrecision);
    m_expression = toEvaluate;
    m_lastResultText = resultText;
    m_openParenCount = 0;
    m_resultShown = true;
    ui->expressionEdit->setPlainText(m_expression + QStringLiteral(" = ") + resultText);
    ui->display->setText(resultText);

    // 【新增】通知外壳（历史停靠窗）：本次求值的表达式与结果。
    emit evaluated(m_expression, resultText);
}

void CalculatorDesigner::onClear() {
    m_expression.clear();
    m_lastResultText.clear();
    m_openParenCount = 0;
    m_resultShown = false;
    m_error = false;
    ui->expressionEdit->clear();
    ui->display->setText(QStringLiteral("0"));
}

void CalculatorDesigner::onBackspace() {
    if (m_error) { onClear(); return; }
    if (m_resultShown) return;  // 结果已展示，需先清空或继续输入新表达式
    if (m_expression.isEmpty()) return;

    const QChar removed = m_expression.at(m_expression.size() - 1);
    m_expression.chop(1);
    if (removed == QLatin1Char('(')) --m_openParenCount;
    else if (removed == QLatin1Char(')')) ++m_openParenCount;
    refreshDisplays();
}

QString CalculatorDesigner::displayText() const { return ui->display->text(); }

QString CalculatorDesigner::expressionText() const { return ui->expressionEdit->toPlainText(); }

// 【新增】把一条历史表达式回填到编辑区：重置状态机并把表达式原样载入，
// 未闭合括号数按字符重新统计。调用后用户可直接按 = 重新求值，或继续编辑。
void CalculatorDesigner::loadExpression(const QString& expr) {
    if (m_error) onClear();
    m_expression = expr;
    m_openParenCount = 0;
    for (const QChar ch : m_expression) {
        if (ch == QLatin1Char('(')) ++m_openParenCount;
        else if (ch == QLatin1Char(')')) --m_openParenCount;
    }
    if (m_openParenCount < 0) m_openParenCount = 0;
    m_resultShown = false;
    m_lastResultText.clear();
    refreshDisplays();
}

QString CalculatorDesigner::currentOperandToken() const {
    int start = m_expression.size();
    while (start > 0 && isDigitOrDotChar(m_expression.at(start - 1))) --start;
    return m_expression.mid(start);
}

int CalculatorDesigner::currentOperandDigitCount() const {
    const QString token = currentOperandToken();
    int count = 0;
    for (const QChar ch : token) {
        if (ch.isDigit()) ++count;
    }
    return count;
}

QString CalculatorDesigner::lastNumberToken() const {
    int end = m_expression.size();
    while (end > 0 && !isDigitOrDotChar(m_expression.at(end - 1))) --end;  // 跳过末尾的运算符/括号
    int start = end;
    while (start > 0 && isDigitOrDotChar(m_expression.at(start - 1))) --start;
    return m_expression.mid(start, end - start);
}

void CalculatorDesigner::refreshDisplays() {
    ui->expressionEdit->setPlainText(m_expression);
    const QString token = lastNumberToken();
    ui->display->setText(token.isEmpty() ? QStringLiteral("0") : token);
}

void CalculatorDesigner::showError() {
    ui->display->setText(QStringLiteral("Error"));
    m_error = true;
}
