/**
 * 自然写互动课堂应用开发SDK软件 V1.0
 * 笔迹平滑算法核心模块 - 笔迹坐标平滑与笔锋渲染
 *
 * 跨平台C语言核心库
 * 提供贝塞尔曲线平滑、笔锋宽度计算、坐标插值等算法
 * 确保各平台SDK输出一致的笔迹渲染效果
 */

#ifndef STROKE_SMOOTHER_H
#define STROKE_SMOOTHER_H

#include <stdint.h>
#include <stddef.h>
#include <math.h>

#ifdef __cplusplus
extern "C" {
#endif

/* ==================== 常量定义 ==================== */

#define MAX_SMOOTH_POINTS   4096    /* 平滑输出点缓冲区大小 */
#define MIN_POINT_DISTANCE  0.5f    /* 最小点间距（低于此值合并） */
#define BEZIER_SEGMENTS     8       /* 贝塞尔曲线分段数 */
#define PRESSURE_SMOOTH_FACTOR 0.3f /* 压力平滑因子 */

/* ==================== 数据结构 ==================== */

/** 二维浮点坐标点 */
typedef struct {
    float x;
    float y;
} Vec2f;

/** 带压力和时间戳的笔迹点 */
typedef struct {
    float x;
    float y;
    float pressure;     /* 0.0-1.0 */
    float width;        /* 计算后的笔画宽度 */
    uint32_t timestamp; /* 时间戳 */
} SmoothPoint;

/** 笔迹平滑器上下文 */
typedef struct {
    /* 输入点缓冲区（最近4个点，用于三次贝塞尔） */
    SmoothPoint input_buffer[4];
    int buffer_count;

    /* 输出点缓冲区 */
    SmoothPoint output_buffer[MAX_SMOOTH_POINTS];
    int output_count;

    /* 笔画宽度配置 */
    float min_width;        /* 最小笔画宽度 */
    float max_width;        /* 最大笔画宽度 */
    float velocity_scale;   /* 速度对宽度的影响系数 */

    /* 上一点的平滑压力值 */
    float last_smooth_pressure;

    /* 统计信息 */
    uint32_t total_input_points;
    uint32_t total_output_points;
} StrokeSmoother;

/* ==================== 数学工具函数 ==================== */

/** 两点间欧氏距离 */
static inline float vec2f_distance(Vec2f a, Vec2f b) {
    float dx = b.x - a.x;
    float dy = b.y - a.y;
    return sqrtf(dx * dx + dy * dy);
}

/** 两点间线性插值 */
static inline Vec2f vec2f_lerp(Vec2f a, Vec2f b, float t) {
    Vec2f result;
    result.x = a.x + (b.x - a.x) * t;
    result.y = a.y + (b.y - a.y) * t;
    return result;
}

/** 浮点数线性插值 */
static inline float float_lerp(float a, float b, float t) {
    return a + (b - a) * t;
}

/** 将值裁剪到范围 [min_val, max_val] */
static inline float float_clamp(float value, float min_val, float max_val) {
    if (value < min_val) return min_val;
    if (value > max_val) return max_val;
    return value;
}

/* ==================== 贝塞尔曲线算法 ==================== */

/**
 * 计算三次贝塞尔曲线上的点
 * B(t) = (1-t)^3*P0 + 3*(1-t)^2*t*P1 + 3*(1-t)*t^2*P2 + t^3*P3
 *
 * 用于平滑连接相邻坐标点，消除折角使笔画圆润
 */
static Vec2f cubic_bezier(Vec2f p0, Vec2f p1, Vec2f p2, Vec2f p3, float t) {
    float u = 1.0f - t;
    float tt = t * t;
    float uu = u * u;
    float uuu = uu * u;
    float ttt = tt * t;

    Vec2f point;
    point.x = uuu * p0.x + 3.0f * uu * t * p1.x + 3.0f * u * tt * p2.x + ttt * p3.x;
    point.y = uuu * p0.y + 3.0f * uu * t * p1.y + 3.0f * u * tt * p2.y + ttt * p3.y;
    return point;
}

/**
 * 使用Catmull-Rom样条生成贝塞尔控制点
 * 从4个数据点(p0,p1,p2,p3)计算p1到p2之间的贝塞尔控制点
 * 确保曲线经过原始数据点（C1连续）
 */
static void catmull_rom_to_bezier(
    Vec2f p0, Vec2f p1, Vec2f p2, Vec2f p3,
    Vec2f* cp1_out, Vec2f* cp2_out
) {
    float tension = 0.5f;  /* 张力系数，0.5为标准Catmull-Rom */
    cp1_out->x = p1.x + (p2.x - p0.x) * tension / 3.0f;
    cp1_out->y = p1.y + (p2.y - p0.y) * tension / 3.0f;
    cp2_out->x = p2.x - (p3.x - p1.x) * tension / 3.0f;
    cp2_out->y = p2.y - (p3.y - p1.y) * tension / 3.0f;
}

/* ==================== 笔画宽度计算 ==================== */

/**
 * 根据压力和速度计算笔画宽度
 * 模拟真实毛笔/钢笔的笔锋效果：
 * - 压力越大，笔画越粗
 * - 速度越快，笔画越细（模拟快写时的飞白效果）
 * - 起笔/收笔处渐变细化
 */
static float calculate_stroke_width(
    float pressure, float velocity,
    float min_width, float max_width, float velocity_scale
) {
    /* 压力影响：压力0→最细，压力1→最粗 */
    float pressure_width = min_width + (max_width - min_width) * pressure;

    /* 速度衰减：速度快时笔画变细 */
    float velocity_factor = 1.0f / (1.0f + velocity * velocity_scale);

    float width = pressure_width * velocity_factor;
    return float_clamp(width, min_width, max_width);
}

/* ==================== 笔迹平滑器API ==================== */

/**
 * 初始化笔迹平滑器
 */
static void smoother_init(StrokeSmoother* ctx, float min_width, float max_width) {
    ctx->buffer_count = 0;
    ctx->output_count = 0;
    ctx->min_width = min_width;
    ctx->max_width = max_width;
    ctx->velocity_scale = 0.005f;
    ctx->last_smooth_pressure = 0.5f;
    ctx->total_input_points = 0;
    ctx->total_output_points = 0;
}

/**
 * 输入一个新的坐标点
 * 当缓冲区积累到4个点时，自动生成贝塞尔曲线平滑点
 * 返回新生成的平滑点数量
 */
static int smoother_add_point(StrokeSmoother* ctx, float x, float y,
                               float pressure, uint32_t timestamp) {
    ctx->total_input_points++;

    /* 压力平滑（低通滤波器，避免压力值跳变） */
    float smooth_pressure = ctx->last_smooth_pressure +
        PRESSURE_SMOOTH_FACTOR * (pressure - ctx->last_smooth_pressure);
    ctx->last_smooth_pressure = smooth_pressure;

    /* 添加到输入缓冲区 */
    int idx = ctx->buffer_count;
    if (idx >= 4) {
        /* 缓冲区满，移位 */
        ctx->input_buffer[0] = ctx->input_buffer[1];
        ctx->input_buffer[1] = ctx->input_buffer[2];
        ctx->input_buffer[2] = ctx->input_buffer[3];
        idx = 3;
    }

    ctx->input_buffer[idx].x = x;
    ctx->input_buffer[idx].y = y;
    ctx->input_buffer[idx].pressure = smooth_pressure;
    ctx->input_buffer[idx].timestamp = timestamp;
    ctx->buffer_count = idx + 1;

    /* 不足4个点时直接输出原始点 */
    if (ctx->buffer_count < 4) {
        if (ctx->output_count < MAX_SMOOTH_POINTS) {
            /* 计算速度和宽度 */
            float velocity = 0;
            if (ctx->buffer_count >= 2) {
                Vec2f prev = {ctx->input_buffer[ctx->buffer_count-2].x, ctx->input_buffer[ctx->buffer_count-2].y};
                Vec2f curr = {x, y};
                float dt = (float)(timestamp - ctx->input_buffer[ctx->buffer_count-2].timestamp);
                if (dt > 0) velocity = vec2f_distance(prev, curr) / dt * 1000.0f;
            }

            float width = calculate_stroke_width(smooth_pressure, velocity,
                ctx->min_width, ctx->max_width, ctx->velocity_scale);

            SmoothPoint sp = {x, y, smooth_pressure, width, timestamp};
            ctx->output_buffer[ctx->output_count++] = sp;
            ctx->total_output_points++;
            return 1;
        }
        return 0;
    }

    /* 4个点准备好，生成贝塞尔曲线 */
    Vec2f p0 = {ctx->input_buffer[0].x, ctx->input_buffer[0].y};
    Vec2f p1 = {ctx->input_buffer[1].x, ctx->input_buffer[1].y};
    Vec2f p2 = {ctx->input_buffer[2].x, ctx->input_buffer[2].y};
    Vec2f p3 = {ctx->input_buffer[3].x, ctx->input_buffer[3].y};

    /* 计算贝塞尔控制点 */
    Vec2f cp1, cp2;
    catmull_rom_to_bezier(p0, p1, p2, p3, &cp1, &cp2);

    /* 在p1到p2之间生成平滑点 */
    int new_points = 0;
    for (int i = 0; i <= BEZIER_SEGMENTS; i++) {
        if (ctx->output_count >= MAX_SMOOTH_POINTS) break;

        float t = (float)i / BEZIER_SEGMENTS;
        Vec2f pt = cubic_bezier(p1, cp1, cp2, p2, t);

        /* 插值压力和时间戳 */
        float interp_pressure = float_lerp(ctx->input_buffer[1].pressure,
                                            ctx->input_buffer[2].pressure, t);
        uint32_t interp_time = (uint32_t)float_lerp(
            (float)ctx->input_buffer[1].timestamp,
            (float)ctx->input_buffer[2].timestamp, t);

        /* 计算速度 */
        float velocity = 0;
        if (ctx->output_count > 0) {
            SmoothPoint* prev = &ctx->output_buffer[ctx->output_count - 1];
            Vec2f prev_v = {prev->x, prev->y};
            float dt = (float)(interp_time - prev->timestamp);
            if (dt > 0) velocity = vec2f_distance(prev_v, pt) / dt * 1000.0f;
        }

        /* 计算笔画宽度 */
        float width = calculate_stroke_width(interp_pressure, velocity,
            ctx->min_width, ctx->max_width, ctx->velocity_scale);

        /* 距离过滤：跳过距上一点太近的点 */
        if (ctx->output_count > 0) {
            SmoothPoint* prev = &ctx->output_buffer[ctx->output_count - 1];
            Vec2f prev_v = {prev->x, prev->y};
            if (vec2f_distance(prev_v, pt) < MIN_POINT_DISTANCE) continue;
        }

        SmoothPoint sp = {pt.x, pt.y, interp_pressure, width, interp_time};
        ctx->output_buffer[ctx->output_count++] = sp;
        ctx->total_output_points++;
        new_points++;
    }

    return new_points;
}

/**
 * 结束当前笔画（抬笔时调用）
 * 输出最后一段贝塞尔曲线的收尾点
 */
static int smoother_end_stroke(StrokeSmoother* ctx) {
    int new_points = 0;

    /* 输出缓冲区中剩余的点 */
    if (ctx->buffer_count >= 2 && ctx->output_count < MAX_SMOOTH_POINTS) {
        int last = ctx->buffer_count - 1;
        float width = calculate_stroke_width(
            ctx->input_buffer[last].pressure * 0.5f, 0,  /* 收笔处宽度减半 */
            ctx->min_width, ctx->max_width, ctx->velocity_scale);

        SmoothPoint sp = {
            ctx->input_buffer[last].x, ctx->input_buffer[last].y,
            ctx->input_buffer[last].pressure, width,
            ctx->input_buffer[last].timestamp
        };
        ctx->output_buffer[ctx->output_count++] = sp;
        new_points++;
    }

    /* 重置输入缓冲区 */
    ctx->buffer_count = 0;
    ctx->last_smooth_pressure = 0.5f;

    return new_points;
}

/**
 * 获取平滑后的输出点
 */
static inline const SmoothPoint* smoother_get_output(const StrokeSmoother* ctx) {
    return ctx->output_buffer;
}

/**
 * 获取输出点数量
 */
static inline int smoother_get_output_count(const StrokeSmoother* ctx) {
    return ctx->output_count;
}

/**
 * 清除输出缓冲区
 */
static inline void smoother_clear_output(StrokeSmoother* ctx) {
    ctx->output_count = 0;
}

/**
 * 获取统计信息
 */
static inline void smoother_get_stats(const StrokeSmoother* ctx,
    uint32_t* input_count, uint32_t* output_count) {
    if (input_count) *input_count = ctx->total_input_points;
    if (output_count) *output_count = ctx->total_output_points;
}

#ifdef __cplusplus
}
#endif

#endif /* STROKE_SMOOTHER_H */
