#ifndef MP3_PLAYER_HPP
#define MP3_PLAYER_HPP

/**
 * @file mp3_player.hpp
 * @brief Advanced MP3 Player with Real-time Audio Analysis
 * 
 * This library provides a feature-rich MP3 player with real-time audio analysis
 * capabilities including beat detection, frequency analysis, and event-driven
 * audio processing suitable for visualization and interactive applications.
 * 
 * @author Audio Analysis Library
 * @version 1.0
 */

#include <string>
#include <vector>
#include <functional>
#include <thread>
#include <atomic>
#include <mutex>
#include <queue>
#include <memory>
#include <chrono>
#include <map>

namespace AudioAnalysis {

/**
 * @brief Frequency band analysis results
 */
struct FrequencyBands {
    double bass;        ///< 20-250 Hz energy (0.0-1.0)
    double low_mid;     ///< 250-500 Hz energy (0.0-1.0)
    double mid;         ///< 500-2000 Hz energy (0.0-1.0)
    double high_mid;    ///< 2000-4000 Hz energy (0.0-1.0)
    double treble;      ///< 4000+ Hz energy (0.0-1.0)
};

/**
 * @brief Comprehensive audio features extracted from audio analysis
 */
struct AudioFeatures {
    double tempo;                  ///< BPM (beats per minute)
    double energy;                 ///< Overall energy level (0.0 - 1.0)
    double spectral_centroid;      ///< Brightness measure
    std::vector<double> spectrum;  ///< Frequency spectrum
    bool beat_detected;            ///< Whether a beat was detected in current frame
    double beat_strength;          ///< Strength of the detected beat (0.0 - 1.0)
    
    // Extended features for advanced visualization
    FrequencyBands freq_bands;     ///< Frequency band analysis
    double dynamics;               ///< Dynamic range (0.0 - 1.0)
    double harmonic_ratio;         ///< Harmonic vs noise content (0.0 - 1.0)
    double zero_crossing_rate;     ///< ZCR for texture analysis
    double spectral_rolloff;       ///< Frequency below which 85% of energy is contained
    double mfcc[13];              ///< Mel-frequency cepstral coefficients (for timbre)
    double onset_strength;         ///< Onset detection strength
    bool silence_detected;         ///< Silence/pause detection
};

/**
 * @brief Types of audio events that can be detected
 */
enum class EventType {
    BEAT,               ///< Beat/rhythm events
    ENERGY_SPIKE,       ///< Sudden energy increases
    FREQ_MODULATION,    ///< Frequency band changes
    HARMONIC_CHANGE,    ///< Harmonic content changes  
    DYNAMIC_CHANGE,     ///< Dynamic range changes
    TEMPO_CHANGE,       ///< Tempo shifts
    ONSET,              ///< Note onsets
    SILENCE,            ///< Silence periods
    CONTINUOUS          ///< Continuous parameter updates
};

/**
 * @brief Audio event with detailed information
 */
struct AudioEvent {
    EventType type;                            ///< Event type
    double timestamp;                          ///< Time when event occurred (seconds)
    double intensity;                          ///< Event intensity (0.0-1.0)
    AudioFeatures features;                    ///< Complete audio features at event time
    std::map<std::string, double> parameters;  ///< Event-specific parameters
};

// Callback function types
using AudioEventCallback = std::function<void(const AudioFeatures&, double position_seconds)>;
using ContinuousCallback = std::function<void(const AudioFeatures&, double position_seconds)>;
using SpecificEventCallback = std::function<void(const AudioEvent&)>;

/**
 * @brief Analysis configuration parameters
 */
struct AnalysisParams {
    // Beat detection
    double beat_sensitivity = 0.3;     ///< Beat detection sensitivity (0.0 - 1.0)
    int window_size = 1024;            ///< Analysis window size
    int hop_size = 512;                ///< Hop size for overlapping windows
    double min_bpm = 60.0;             ///< Minimum BPM to detect
    double max_bpm = 180.0;            ///< Maximum BPM to detect
    
    // Feature extraction
    bool enable_freq_bands = true;     ///< Enable frequency band analysis
    bool enable_mfcc = true;           ///< Enable MFCC calculation
    bool enable_harmonic_analysis = true; ///< Enable harmonic analysis
    
    // Event thresholds
    double energy_spike_threshold = 0.7;      ///< Threshold for energy spike events
    double dynamic_change_threshold = 0.3;    ///< Threshold for dynamic change events
    double tempo_change_threshold = 5.0;      ///< BPM change threshold for tempo events
    double freq_modulation_threshold = 0.2;   ///< Threshold for frequency modulation events
    
    // Continuous monitoring
    int continuous_update_rate_ms = 50;       ///< How often to send continuous updates (ms)
    bool enable_continuous_monitoring = true; ///< Enable continuous parameter monitoring
};

/**
 * @brief Legacy beat detection parameters (for backward compatibility)
 */
struct BeatDetectionParams {
    double sensitivity = 0.3;     ///< Beat detection sensitivity (0.0 - 1.0)
    int window_size = 1024;       ///< Analysis window size
    int hop_size = 512;           ///< Hop size for overlapping windows
    double min_bpm = 60.0;        ///< Minimum BPM to detect
    double max_bpm = 180.0;       ///< Maximum BPM to detect
};

/** Single detected event for offline timeline export */
struct OfflineEventMarker {
    double time = 0.0;
    EventType type = EventType::ONSET;
    double intensity = 0.0;
};

/** Heuristic phrase / section boundary from energy + silence */
struct OfflinePhraseSegment {
    double start = 0.0;
    double end = 0.0;
    double mean_energy = 0.0;
    int beat_count = 0;
};

/** Full-file scan result (no playback required) */
struct OfflineAnalysisResult {
    std::string file;
    double duration = 0.0;
    double tempo_bpm = 0.0;
    double envelope_step = 0.05;
    std::vector<double> envelope_times;
    std::vector<double> envelope_energy;
    std::vector<double> beat_times;
    std::vector<OfflineEventMarker> events;
    std::vector<OfflinePhraseSegment> phrases;
};

/**
 * @brief Advanced MP3 Player with Real-time Audio Analysis
 * 
 * This class provides a complete MP3 playback system with extensive real-time
 * audio analysis capabilities. It can detect beats, analyze frequency content,
 * track tempo changes, and trigger events based on musical characteristics.
 * 
 * Features:
 * - MP3 playback with full transport controls
 * - Real-time beat detection and tempo tracking
 * - Frequency band analysis (bass, mid, treble)
 * - Harmonic content analysis
 * - Multiple event callback systems
 * - Continuous parameter monitoring for smooth visualization
 * 
 * Example usage:
 * @code
 * AudioAnalysis::MP3Player player;
 * player.load("song.mp3");
 * 
 * // Register beat callback
 * player.add_event_callback([](const AudioFeatures& features, double pos) {
 *     if (features.beat_detected) {
 *         std::cout << "Beat at " << pos << "s!" << std::endl;
 *     }
 * });
 * 
 * player.play();
 * @endcode
 */
class MP3Player {
private:
    struct AudioBuffer {
        std::vector<float> data;
        size_t size;
        size_t channels;
        int sample_rate;
    };

    // Core audio state
    AudioBuffer current_buffer;
    std::atomic<bool> is_playing{false};
    std::atomic<bool> is_paused{false};
    std::atomic<bool> should_stop{false};
    std::atomic<bool> loop_enabled{true};
    std::atomic<double> position_seconds{0.0};
    std::atomic<double> duration_seconds{0.0};
    
    // Threading
    std::thread playback_thread;
    std::thread analysis_thread;
    std::thread continuous_monitor_thread;
    std::mutex audio_mutex;
    
    // Audio analysis
    BeatDetectionParams beat_params;
    AnalysisParams analysis_params;
    std::vector<double> energy_history;
    std::vector<double> beat_times;
    double current_tempo = 0.0;
    
    // Previous values for change detection
    double prev_harmonic_ratio = 0.0;
    double prev_dynamics = 0.0;
    FrequencyBands prev_freq_bands = {0,0,0,0,0};
    
    // Event system
    std::vector<AudioEventCallback> event_callbacks;
    std::vector<ContinuousCallback> continuous_callbacks;
    std::vector<SpecificEventCallback> specific_event_callbacks;
    std::mutex callback_mutex;
    
    // Continuous monitoring
    std::chrono::steady_clock::time_point last_continuous_update;
    
    // Private methods
    bool load_mp3_file(const std::string& filename);
    void audio_playback_loop();
    void audio_analysis_loop();
    void continuous_monitoring_loop();
    void process_audio_frame(const float* samples, size_t frame_size);
    AudioFeatures analyze_audio_features(const float* samples, size_t frame_size);
    bool detect_beat(const std::vector<double>& spectrum, double energy);
    double calculate_tempo();
    void trigger_events(const AudioFeatures& features);
    void check_and_trigger_specific_events(const AudioFeatures& features);
    std::vector<double> compute_fft(const float* samples, size_t size);
    double calculate_spectral_centroid(const std::vector<double>& spectrum);
    
    // Extended analysis methods
    FrequencyBands analyze_frequency_bands(const std::vector<double>& spectrum, int sample_rate);
    double calculate_harmonic_ratio(const std::vector<double>& spectrum);
    double calculate_dynamics(const float* samples, size_t frame_size);
    double calculate_zero_crossing_rate(const float* samples, size_t frame_size);
    double calculate_spectral_rolloff(const std::vector<double>& spectrum);
    void calculate_mfcc(const std::vector<double>& spectrum, double* mfcc_out);
    double calculate_onset_strength(const std::vector<double>& spectrum, const std::vector<double>& prev_spectrum);
    bool detect_silence(const float* samples, size_t frame_size);

    void reset_offline_analysis_state();
    void collect_offline_events(const AudioFeatures& features, double timestamp,
                                OfflineAnalysisResult& result,
                                double& last_energy_spike, double& last_onset,
                                double& last_freq_mod, double& last_harmonic,
                                double& last_dynamic,
                                bool& in_silence, double& silence_start);
    void build_offline_phrases(OfflineAnalysisResult& result);

public:
    /**
     * @brief Constructor
     */
    MP3Player();
    
    /**
     * @brief Destructor - automatically stops playback and cleans up
     */
    ~MP3Player();
    
    // ===== PLAYBACK CONTROL =====
    
    /**
     * @brief Load an MP3 file for playback
     * @param filename Path to the MP3 file
     * @return true if successful, false otherwise
     */
    bool load(const std::string& filename);
    
    /**
     * @brief Start or resume playback
     * @return true if successful, false otherwise
     */
    bool play();
    
    /**
     * @brief Pause or resume playback
     * @return true if successful, false otherwise
     */
    bool pause();
    
    /**
     * @brief Stop playback and return to beginning
     * @return true if successful, false otherwise
     */
    bool stop();
    
    /**
     * @brief Check if a file is loaded
     * @return true if a file is loaded, false otherwise
     */
    bool is_loaded() const;
    
    // ===== POSITION CONTROL =====
    
    /**
     * @brief Seek to a specific position in the track
     * @param seconds Position in seconds
     * @return true if successful, false otherwise
     */
    bool seek(double seconds);
    
    /**
     * @brief Get current playback position
     * @return Current position in seconds
     */
    double get_position() const { return position_seconds.load(); }
    
    /**
     * @brief Get total track duration
     * @return Duration in seconds
     */
    double get_duration() const { return duration_seconds.load(); }
    
    // ===== VOLUME CONTROL =====
    
    /**
     * @brief Set playback volume
     * @param volume Volume level (0.0 - 1.0)
     */
    void set_volume(double volume);
    
    /**
     * @brief Get current volume
     * @return Current volume (0.0 - 1.0)
     */
    double get_volume() const;
    
    // ===== ANALYSIS CONFIGURATION =====
    
    /**
     * @brief Set analysis parameters
     * @param params Analysis configuration
     */
    void set_analysis_params(const AnalysisParams& params);
    
    /**
     * @brief Get current analysis parameters
     * @return Current analysis configuration
     */
    AnalysisParams get_analysis_params() const { return analysis_params; }
    
    /**
     * @brief Set beat detection parameters (legacy compatibility)
     * @param params Beat detection configuration
     */
    void set_beat_detection_params(const BeatDetectionParams& params);
    
    /**
     * @brief Get beat detection parameters (legacy compatibility)
     * @return Current beat detection configuration
     */
    BeatDetectionParams get_beat_detection_params() const { return beat_params; }
    
    // ===== EVENT SYSTEM =====
    
    /**
     * @brief Add callback for general audio events
     * @param callback Function to call on audio events
     */
    void add_event_callback(AudioEventCallback callback);
    
    /**
     * @brief Add callback for continuous parameter monitoring
     * @param callback Function to call for continuous updates
     */
    void add_continuous_callback(ContinuousCallback callback);
    
    /**
     * @brief Add callback for specific event types
     * @param callback Function to call for specific events
     */
    void add_specific_event_callback(SpecificEventCallback callback);
    
    /**
     * @brief Clear all general event callbacks
     */
    void clear_event_callbacks();
    
    /**
     * @brief Clear all continuous monitoring callbacks
     */
    void clear_continuous_callbacks();
    
    /**
     * @brief Clear all specific event callbacks
     */
    void clear_specific_event_callbacks();
    
    /**
     * @brief Clear all callbacks
     */
    void clear_all_callbacks();
    
    // ===== REAL-TIME DATA ACCESS =====
    
    /**
     * @brief Get current audio features
     * @return Current audio analysis results
     */
    AudioFeatures get_current_features() const;
    
    /**
     * @brief Get current tempo
     * @return Current tempo in BPM
     */
    double get_current_tempo() const { return current_tempo; }
    
    /**
     * @brief Get current frequency bands
     * @return Current frequency band analysis
     */
    FrequencyBands get_current_frequency_bands() const;
    
    /**
     * @brief Get current dynamic range
     * @return Current dynamic range (0.0-1.0)
     */
    double get_current_dynamics() const;
    
    /**
     * @brief Get current harmonic ratio
     * @return Current harmonic content ratio (0.0-1.0)
     */
    double get_current_harmonic_ratio() const;
    
    // ===== UTILITY =====
    
    /**
     * @brief Get currently loaded filename
     * @return Filename of currently loaded track
     */
    std::string get_current_file() const { return current_filename; }
    
    /**
     * @brief Get playback state
     * @return true if playing, false otherwise
     */
    bool get_playback_state() const { return is_playing.load(); }

    /** @brief When false, playback stops at end of track instead of looping. */
    void set_loop(bool enabled) { loop_enabled.store(enabled); }
    bool get_loop() const { return loop_enabled.load(); }

    /**
     * @brief Scan the loaded file and extract beats, envelope, and events.
     * Requires load() first; does not start playback.
     * @param envelope_step_sec Sample interval for the energy envelope curve
     */
    OfflineAnalysisResult analyze_offline(double envelope_step_sec = 0.05);

private:
    std::string current_filename;
    double current_volume = 1.0;
    mutable std::mutex features_mutex;
    AudioFeatures current_features;
    std::vector<double> prev_spectrum; // For onset detection
};

} // namespace AudioAnalysis

#endif // MP3_PLAYER_HPP 