#include "et_waveform_analysis.h"
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

#ifndef WAVE_DEBUG
#define WAVE_DEBUG 0
#endif

#if WAVE_DEBUG
#define DEBUG_PRINT(...) DEBUG_PRINT(__VA_ARGS__)
#else
#define DEBUG_PRINT(...)
#endif
/**
 * @brief Initialize waveform analysis structure preserving zero crossing data
 * @param analysis Pointer to et_waveform_analysis_t structure
 */
static void reset_analysis_preserving_zc(et_waveform_analysis_t *analysis)
{
    if (analysis == NULL)
        return;

    // Save zero crossing related data
    float   *saved_buf         = analysis->zc.pos_buf;
    uint32_t saved_buf_size    = analysis->zc.max_pos_size;
    float    saved_thresh_low  = analysis->zc.thresh_low;
    float    saved_thresh_high = analysis->zc.thresh_high;

    // Reset all fields
    memset(analysis, 0, sizeof(et_waveform_analysis_t));

    // Restore zero crossing data
    analysis->zc.pos_buf      = saved_buf;
    analysis->zc.max_pos_size = saved_buf_size;
    analysis->zc.thresh_low   = saved_thresh_low;
    analysis->zc.thresh_high  = saved_thresh_high;

    // Initialize peak values
    analysis->first_peak  = -FLT_MAX;
    analysis->second_peak = -FLT_MAX;
}

/**
 * @brief Analyze a single half-cycle segment
 * @param point Pointer to input et_zc_point_t array
 * @param offset DC offset to subtract
 * @param start_idx Starting index of the segment
 * @param end_idx Ending index of the segment
 * @param is_first_half Flag indicating if this is the first half-cycle
 * @param analysis Pointer to et_waveform_analysis_t structure for storing results
 */
static void analyze_half_cycle(const et_zc_point_t *point, uint16_t offset, uint32_t start_idx, uint32_t end_idx,
                               int is_first_half, et_waveform_analysis_t *analysis)
{
    // Find peak in this segment
    float    peak_val = -FLT_MAX;
    uint32_t peak_idx = start_idx;

    // Also track the minimum value to determine if this is a positive or negative half-cycle
    float    min_val = FLT_MAX;
    uint32_t min_idx = start_idx;

    float    segment_sum   = 0.0f;
    uint32_t segment_count = 0;

    for (uint32_t j = start_idx; j < end_idx; j++)
    {
        float val    = (float)point[j].val - offset;
        segment_sum += val;
        segment_count++;

        if (val > peak_val)
        {
            peak_val = val;
            peak_idx = j;
        }

        if (val < min_val)
        {
            min_val = val;
            min_idx = j;
        }
    }

    // Determine if this is a positive or negative half-cycle based on which extreme is further from zero
    int      is_positive = (fabs(peak_val) >= fabs(min_val));
    float    extreme_val = is_positive ? peak_val : min_val;
    uint32_t extreme_idx = is_positive ? peak_idx : min_idx;

    // Store the absolute value of the extreme (peak or trough) - compute once
    float abs_extreme_val = fabs(extreme_val);

    // Update overall analysis
    if (is_first_half)
    {
        analysis->first_mean       = segment_sum / segment_count;
        analysis->first_sample_cnt = segment_count;

        if (abs_extreme_val > analysis->first_peak)
        {
            analysis->first_peak     = abs_extreme_val;
            analysis->first_peak_idx = extreme_idx;
            DEBUG_PRINT("New first peak: %f\n", analysis->first_peak);
        }
    }
    else
    {
        analysis->second_mean       = segment_sum / segment_count;
        analysis->second_sample_cnt = segment_count;

        if (abs_extreme_val > analysis->second_peak)
        {
            analysis->second_peak     = abs_extreme_val;
            analysis->second_peak_idx = extreme_idx;
            DEBUG_PRINT("New second peak: %f\n", analysis->second_peak);
        }
    }
}

/**
 * @brief Create and initialize a waveform analysis structure
 * @param analysis Pointer to et_waveform_analysis_t structure
 * @return int      0 on success, -1 on failure
 */
int et_waveform_analysis_create(et_waveform_analysis_t *analysis, uint32_t max_pos)
{
    if (analysis == NULL)
        return -1;

    // Initialize all fields to zero
    memset(analysis, 0, sizeof(et_waveform_analysis_t));
    if (et_zero_cross_create(&analysis->zc, max_pos) != 0) // Using a default length
        return -1;
    return 0;
}

void et_waveform_analysis_destroy(et_waveform_analysis_t *analysis)
{
    if (analysis != NULL)
        et_zero_cross_destroy(&analysis->zc);
}

/**
 * @brief Analyze waveform characteristics (et_zc_point_t input)
 * @param analysis Pointer to et_waveform_analysis_t structure for storing results
 * @param point    Pointer to input et_zc_point_t array
 * @param length   Number of samples
 * @param offset   DC offset to subtract
 * @return int     0 on success, -1 on failure
 */
int et_waveform_analyze_point(et_waveform_analysis_t *analysis, const et_zc_point_t *point, uint32_t length,
                              uint16_t offset)
{
    if (analysis == NULL || point == NULL || length < 2)
        return -1;

    // Reset analysis structure (but preserve zc.pos_buf)
    reset_analysis_preserving_zc(analysis);

    // Get zero crossing positions using existing function
    analysis->zc_count = et_zero_cross_pos_point(&analysis->zc, point, length, offset);

    // Analyze consecutive half-cycle pairs
    // Need at least 3 zero crossing points to define a complete cycle
    if (analysis->zc_count >= 3)
    {
        // Only analyze the first pair of consecutive half-cycles (A~B and B~C)
        // First half-cycle (from A to B)
        uint32_t first_start = 0;                                 // Start from the beginning of data
        uint32_t first_end   = (uint32_t)analysis->zc.pos_buf[0]; // First zero crossing (point B)

        // Second half-cycle (from B to C)
        uint32_t second_start = (uint32_t)analysis->zc.pos_buf[0]; // First zero crossing (point B)
        uint32_t second_end   = (uint32_t)analysis->zc.pos_buf[1]; // Second zero crossing (point C)

        // Analyze the first half-cycle (A to B)
        analyze_half_cycle(point, offset, first_start, first_end, 1, analysis);

        // Analyze the second half-cycle (B to C)
        analyze_half_cycle(point, offset, second_start, second_end, 0, analysis);
    }
    else
    {
        return -2;
    }

    // Calculate similarity ratio (1.0 = perfect symmetry)
    float max_peak = fmaxf(analysis->first_peak, analysis->second_peak);

    if (max_peak > 0.0f)
    {
        float min_peak      = fminf(analysis->first_peak, analysis->second_peak);
        analysis->sim_ratio = min_peak / max_peak;
    }
    else
    {
        analysis->sim_ratio = 0.0f;
    }

    return 0;
}

/**
 * @brief Detect similar waveform state where both half-cycles are in positive axis with equal amplitude
 * @param analysis     Pointer to et_waveform_analysis_t structure with analysis results
 * @param threshold    Similarity threshold (0.0-1.0, smaller value means stricter similarity requirement)
 * @return int         1 if similar state detected, 0 otherwise
 */
int et_waveform_detect_similarity(et_waveform_analysis_t *analysis, float threshold)
{
    if (analysis == NULL || threshold < 0.0f || threshold > 1.0f)
        return 0;

    // Check if both positive and negative peaks are positive (indicating the negative half has flipped)
    if (analysis->first_peak <= 0.0f || analysis->second_peak <= 0.0f)
        return 0;

    // Check if similarity ratio is above the threshold
    if (analysis->sim_ratio < (1.0f - threshold))
        return 0;

    // Check if we have a reasonable number of zero crossings
    if (analysis->zc_count < 3)
        return 0;

    return 1;
}

float et_waveform_peak_diff(const et_waveform_analysis_t *analysis)
{
    return fabsf(analysis->first_peak - analysis->second_peak);
}

float et_waveform_peak_ratio(const et_waveform_analysis_t *analysis)
{
    if (analysis == NULL)
        return 0.0f;

    // Avoid division by zero
    if (fabsf(analysis->second_peak) < FLT_EPSILON)
        return 0.0f;

    return analysis->first_peak / analysis->second_peak;
}

/**
 * @brief Calculate the ratio between positive and negative mean values
 * @param analysis Pointer to et_waveform_analysis_t structure with analysis results
 * @return float    Ratio between positive and negative mean values
 */
float et_waveform_mean_ratio(const et_waveform_analysis_t *analysis)
{
    if (analysis == NULL)
        return 0.0f;

    // Avoid division by zero
    if (fabsf(analysis->second_mean) < FLT_EPSILON)
        return 0.0f;

    return analysis->first_mean / analysis->second_mean;
}

/**
 * @brief Calculate the difference between positive and negative mean values
 * @param analysis Pointer to et_waveform_analysis_t structure with analysis results
 * @return float    Difference between positive and negative mean values
 */
float et_waveform_mean_diff(const et_waveform_analysis_t *analysis)
{
    if (analysis == NULL)
        return 0.0f;

    return fabsf(analysis->first_mean - analysis->second_mean);
}

/**
 * @brief Detect if mean values are balanced within a threshold
 * @param analysis Pointer to et_waveform_analysis_t structure with analysis results
 * @param threshold Balance threshold (0.0-1.0)
 * @return int     1 if mean values are balanced, 0 otherwise
 */
int et_waveform_mean_balanced(const et_waveform_analysis_t *analysis, float threshold)
{
    if (analysis == NULL || threshold < 0.0f || threshold > 1.0f)
        return 0;

    float max_mean = fmaxf(analysis->first_mean, analysis->second_mean);

    if (fabsf(max_mean) < FLT_EPSILON)
        return 0;

    float min_mean = fminf(analysis->first_mean, analysis->second_mean);

    // Calculate balance ratio (0.0 = completely unbalanced, 1.0 = perfectly balanced)
    float balance_ratio = fabsf(min_mean / max_mean);

    return (balance_ratio >= (1.0f - threshold));
}

/**
 * @brief Calculate the ratio of sample counts between positive and negative half-cycles
 * @param analysis Pointer to et_waveform_analysis_t structure with analysis results
 * @return float    Ratio of positive to negative sample counts
 */
float et_waveform_sample_count_ratio(const et_waveform_analysis_t *analysis)
{
    if (analysis == NULL || analysis->second_sample_cnt == 0)
        return 0.0f;

    return (float)analysis->first_sample_cnt / (float)analysis->second_sample_cnt;
}

/**
 * @brief Analyze consecutive half-cycles defined by three zero crossings
 * @param analysis Pointer to et_waveform_analysis_t structure for storing results
 * @param point    Pointer to input et_zc_point_t array
 * @param length   Number of samples
 * @param offset   DC offset to subtract
 * @return int     0 on success, -1 on failure
 */
int et_waveform_analyze_consecutive_half_cycles(et_waveform_analysis_t *analysis, const et_zc_point_t *point,
                                                uint32_t length, uint16_t offset)
{
    if (analysis == NULL || point == NULL || length < 3)
        return -1;

    // Reset analysis structure (but preserve zc.pos_buf)
    reset_analysis_preserving_zc(analysis);

    // Get zero crossing positions using existing function
    analysis->zc_count = et_zero_cross_pos_point(&analysis->zc, point, length, offset);

    // Need at least 3 zero crossings to define two consecutive half-cycles
    if (analysis->zc_count < 3)
        return -1;

    // Analyze the first half-cycle (from the first zero crossing to the second zero crossing)
    uint32_t first_start = 0;                                 // Start from the beginning of data
    uint32_t first_end   = (uint32_t)analysis->zc.pos_buf[0]; // First zero crossing

    // Analyze the second half-cycle (from the first zero crossing to the second zero crossing)
    uint32_t second_start = (uint32_t)analysis->zc.pos_buf[0]; // First zero crossing
    uint32_t second_end   = (uint32_t)analysis->zc.pos_buf[1]; // Second zero crossing

    // Analyze the first half-cycle
    analyze_half_cycle(point, offset, first_start, first_end, 1, analysis);

    // Analyze the second half-cycle
    analyze_half_cycle(point, offset, second_start, second_end, 0, analysis);

    // Calculate similarity ratio
    float max_peak = fmaxf(analysis->first_peak, analysis->second_peak);
    DEBUG_PRINT("max_peak: %.2f\n", max_peak);

    if (max_peak > 0.0f)
    {
        float min_peak      = fminf(analysis->first_peak, analysis->second_peak);
        analysis->sim_ratio = min_peak / max_peak;
    }
    else
    {
        analysis->sim_ratio = 0.0f;
    }

    return 0;
}

/**
 * @brief Calculate the similarity ratio between consecutive half-cycles
 * @param analysis Pointer to et_waveform_analysis_t structure with analysis results
 * @return float    Similarity ratio (1.0 = identical, 0.0 = completely different)
 */
float et_waveform_sim_ratio(const et_waveform_analysis_t *analysis)
{
    if (analysis == NULL)
        return 0.0f;

    // 添加调试信息
    DEBUG_PRINT("调试信息: first_peak=%.2f, second_peak=%.2f\n", analysis->first_peak, analysis->second_peak);
    DEBUG_PRINT("调试信息: sim_ratio=%.4f\n", analysis->sim_ratio);

    // 直接返回已计算的相似性比率，而不是重新计算
    return analysis->sim_ratio;
}


