// ============================================================================
//  mandelbrot_strip_task —— Day4 Mandelbrot 渲染器的「分块计算 + 调色板」单元
//  职责：
//    * MandelViewport   : 视口参数（复平面中心 / 像素跨度 / 尺寸 / 最大迭代）
//    * MandelPalette    : 迭代次数→RGB 的预计算调色板（提升趣味，与知识点无关）
//    * renderStrip()    : 纯计算函数，渲染视口内 [y0,y1) 行像素。多线程 task 与
//                         「主线程卡死」演示路径共用它——保证两路径算的是同一份分形，
//                         差异只在「是否阻塞事件循环 / 是否并行」。
//    * MandelbrotStripTask : 一条水平带的 QRunnable 任务。多继承 QObject+QRunnable
//                         以获得信号能力（QRunnable 本身无信号——这是初学者高频困惑，
//                         见 README 踩坑点 2）。
//  设计要点：task 持 palette/viewport 的【值副本】，自包含、不引用主线程对象，
//           避免主对象先析构导致的悬垂访问（见 README 踩坑点 4）。
// ============================================================================
#ifndef MANDELBROT_STRIP_TASK_H
#define MANDELBROT_STRIP_TASK_H

#include <QImage>
#include <QObject>
#include <QRunnable>
#include <QRgb>
#include <QVector>

// 视口参数：复平面映射。scale = 每像素对应的复平面跨度。
struct MandelViewport {
    double centerX = -0.5;   // 经典 Mandelbrot 主分形居中
    double centerY = 0.0;
    double scale = 3.0 / 600.0;
    int width = 0;           // show 后由 widget 尺寸填入
    int height = 0;
    int maxIter = 256;
};

// 调色板：迭代次数 → RGB。集合内部（迭代未逃逸）映射为黑。
class MandelPalette {
public:
    explicit MandelPalette(int maxIter = 256);
    QRgb color(int i) const { return table_.at(i); }
private:
    QVector<QRgb> table_;
};

// 纯计算：渲染视口内 [y0, y1) 行像素，返回 (width × (y1-y0)) 的 RGB32 QImage。
QImage renderStrip(const MandelViewport& vp, const MandelPalette& pal, int y0, int y1);

// 一条水平带的多线程任务。多继承 QObject + QRunnable 以拥有信号。
// setAutoDelete(true)（默认）：run() 结束后由线程池回收；不设 QObject parent，
// 避免与 QThreadPool 的自动删除发生双重所有权——见 README 踩坑点 2。
class MandelbrotStripTask : public QObject, public QRunnable {
    Q_OBJECT
public:
    MandelbrotStripTask(quint64 epoch, int stripIndex,
                        const MandelViewport& vp, const MandelPalette& pal,
                        int y0, int y1)
        : QObject(nullptr), epoch_(epoch), stripIndex_(stripIndex),
          vp_(vp), pal_(pal), y0_(y0), y1_(y1) { setAutoDelete(true); }

    void run() override {
        // 算完一条带 → 通过信号把结果「排队」送回主线程（Qt 自动跨线程调度）。
        emit stripReady(epoch_, stripIndex_, renderStrip(vp_, pal_, y0_, y1_));
    }

signals:
    void stripReady(quint64 epoch, int stripIndex, QImage strip);

private:
    quint64 epoch_;
    int stripIndex_;
    MandelViewport vp_;
    MandelPalette pal_;   // 值副本：任务自包含
    int y0_;
    int y1_;
};

#endif // MANDELBROT_STRIP_TASK_H
