#ifndef STACKER_SETTINGS_H
#define STACKER_SETTINGS_H

#include <memory>
#include <string>

/**
 * @brief The StackerSettings class manages settings for the stacking process.
 *
 * This class provides a centralized way to manage settings for the stacking process,
 * including flags to track which settings have been explicitly set by the user.
 * It can be shared across different components of the application.
 */
class StackerSettings
{
    public:
        /**
         * @brief Enum for the denoising method
         */
        enum class DenoisingMethod
        {
            None,           ///< No denoising
            NonLocalMeans,  ///< Non-local means denoising
            Bilateral       ///< Bilateral filter
        };

        /**
         * @brief Construct a new StackerSettings object with default values
         */
        StackerSettings()
            : m_alignFrames(true)
            , m_maxAlignmentStars(200)
            , m_backgroundAdjustment(15.0f)  // Remove background noise
            , m_contrastAdjustment(120.0f)   // Internal value (equivalent to input value of ~58)
            , m_saturationAdjustment(120.0f) // Internal value (equivalent to input value of 60)
            , m_compressionPercentage(20.0f) // Bring out faint details
            , m_medianFilterSize(0)
            , m_sigmaClippingFrames(5)       // Enable sigma clipping by default
            , m_sigmaClippingLower(2.0f)     // Lower sigma threshold
            , m_sigmaClippingUpper(2.0f)     // Upper sigma threshold
            , m_diagnosticMode(false)
            , m_outputPrefix("frame_")
            , m_qualityThreshold(0.7f)       // Default quality threshold
            , m_localHistEqWindowSize(0)     // Disabled by default
            , m_localHistEqClipLimit(2.0f)   // Default clip limit
            , m_verboseMode(false)           // Verbose mode disabled by default
            , m_benchmarkMode(false)         // Benchmark mode disabled by default
            , m_denoisingMethod(DenoisingMethod::None) // No denoising by default
            , m_denoisingStrength(10)        // Default strength (1-30)
            , m_autoDetectNebulosity(true)   // Enable nebulosity detection by default
            , m_nebulosityThreshold(0.6f)    // Default nebulosity detection threshold
            , m_backgroundAdjustmentSet(false)
            , m_contrastAdjustmentSet(false)
            , m_saturationAdjustmentSet(false)
            , m_compressionPercentageSet(false)
            , m_medianFilterSizeSet(false)
            , m_localHistEqSet(false)
            , m_denoisingSet(false)
            , m_autoDetectNebulositySet(false)
            , m_nebulosityThresholdSet(false)
        {
        }

        /**
         * @brief Create a shared instance of StackerSettings
         * @return A shared pointer to a new StackerSettings instance
         */
        static std::shared_ptr<StackerSettings> create()
        {
            return std::make_shared<StackerSettings>();
        }

        // Getters and setters for all settings

        bool getAlignFrames() const
        {
            return m_alignFrames;
        }
        void setAlignFrames(bool align)
        {
            m_alignFrames = align;
        }

        int getMaxAlignmentStars() const
        {
            return m_maxAlignmentStars;
        }
        void setMaxAlignmentStars(int maxStars)
        {
            m_maxAlignmentStars = std::max(3, maxStars);
        }

        float getBackgroundAdjustment() const
        {
            return m_backgroundAdjustment;
        }
        void setBackgroundAdjustment(float percentage)
        {
            m_backgroundAdjustment = std::max(0.0f, std::min(100.0f, percentage));
            m_backgroundAdjustmentSet = true;
        }
        bool isBackgroundAdjustmentSet() const
        {
            return m_backgroundAdjustmentSet;
        }

        // Get the internal contrast adjustment value (10-200 range)
        float getContrastAdjustment() const
        {
            return m_contrastAdjustment;
        }

        // Get the user-facing contrast adjustment value (0-100 range)
        float getContrastAdjustmentInput() const
        {
            // Convert from internal range (10-200) to input range (0-100)
            return (m_contrastAdjustment - 10.0f) / 190.0f * 100.0f;
        }
        void setContrastAdjustment(float percentage)
        {
            // Map input range (0-100) to internal range (10-200)
            // 0 -> 10%, 50 -> 100%, 100 -> 200%
            float mappedValue = 10.0f + (percentage / 100.0f) * 190.0f;
            m_contrastAdjustment = std::max(10.0f, std::min(200.0f, mappedValue));
            m_contrastAdjustmentSet = true;
        }
        bool isContrastAdjustmentSet() const
        {
            return m_contrastAdjustmentSet;
        }

        // Get the internal saturation adjustment value (0-200 range)
        float getSaturationAdjustment() const
        {
            return m_saturationAdjustment;
        }

        // Get the user-facing saturation adjustment value (0-100 range)
        float getSaturationAdjustmentInput() const
        {
            // Convert from internal range (0-200) to input range (0-100)
            return m_saturationAdjustment / 200.0f * 100.0f;
        }
        void setSaturationAdjustment(float percentage)
        {
            // Map input range (0-100) to internal range (0-200)
            // 0 -> 0%, 50 -> 100%, 100 -> 200%
            float mappedValue = (percentage / 100.0f) * 200.0f;
            m_saturationAdjustment = std::max(0.0f, std::min(200.0f, mappedValue));
            m_saturationAdjustmentSet = true;
        }
        bool isSaturationAdjustmentSet() const
        {
            return m_saturationAdjustmentSet;
        }

        float getCompressionPercentage() const
        {
            return m_compressionPercentage;
        }
        void setCompressionPercentage(float percentage)
        {
            m_compressionPercentage = std::max(0.0f, std::min(100.0f, percentage));
            m_compressionPercentageSet = true;
        }
        bool isCompressionPercentageSet() const
        {
            return m_compressionPercentageSet;
        }

        int getMedianFilterSize() const
        {
            return m_medianFilterSize;
        }
        void setMedianFilterSize(int size)
        {
            // Ensure size is 0 (disabled) or an odd number
            if (size > 0 && size % 2 == 0)
                size++; // Make it odd
            m_medianFilterSize = std::max(0, size);
            m_medianFilterSizeSet = true;
        }
        bool isMedianFilterSizeSet() const
        {
            return m_medianFilterSizeSet;
        }

        int getSigmaClippingFrames() const
        {
            return m_sigmaClippingFrames;
        }
        float getSigmaClippingLower() const
        {
            return m_sigmaClippingLower;
        }
        float getSigmaClippingUpper() const
        {
            return m_sigmaClippingUpper;
        }
        void setSigmaClippingParams(int frames, float lower, float upper)
        {
            m_sigmaClippingFrames = std::max(3, frames);
            m_sigmaClippingLower = std::max(1.0f, std::min(7.0f, lower));
            m_sigmaClippingUpper = std::max(1.0f, std::min(7.0f, upper));
        }

        bool getDiagnosticMode() const
        {
            return m_diagnosticMode;
        }
        std::string getOutputPrefix() const
        {
            return m_outputPrefix;
        }
        void setDiagnosticMode(bool enable, const std::string &outputPrefix = "frame_")
        {
            m_diagnosticMode = enable;
            m_outputPrefix = outputPrefix;
        }

        float getQualityThreshold() const
        {
            return m_qualityThreshold;
        }
        void setQualityThreshold(float threshold)
        {
            m_qualityThreshold = std::max(0.0f, std::min(1.0f, threshold));
        }

        int getLocalHistEqWindowSize() const
        {
            return m_localHistEqWindowSize;
        }
        float getLocalHistEqClipLimit() const
        {
            return m_localHistEqClipLimit;
        }
        void setLocalHistogramEqualizationParams(int windowSize, float clipLimit)
        {
            // Ensure window size is odd
            if (windowSize > 0 && windowSize % 2 == 0)
                windowSize++; // Make it odd
            m_localHistEqWindowSize = std::max(0, windowSize);
            m_localHistEqClipLimit = std::max(0.0f, std::min(4.0f, clipLimit));
            m_localHistEqSet = true;
        }
        bool isLocalHistEqSet() const
        {
            return m_localHistEqSet;
        }

        // Denoising settings
        DenoisingMethod getDenoisingMethod() const
        {
            return m_denoisingMethod;
        }
        int getDenoisingStrength() const
        {
            return m_denoisingStrength;
        }
        void setDenoising(DenoisingMethod method, int strength)
        {
            m_denoisingMethod = method;
            m_denoisingStrength = std::max(1, std::min(30, strength)); // Clamp to 1-30 range
            m_denoisingSet = true;
        }
        bool isDenoisingSet() const
        {
            return m_denoisingSet;
        }

        // Benchmark mode settings
        bool getBenchmarkMode() const
        {
            return m_benchmarkMode;
        }
        void setBenchmarkMode(bool enable)
        {
            m_benchmarkMode = enable;
        }

        // Nebulosity detection settings
        bool getAutoDetectNebulosity() const
        {
            return m_autoDetectNebulosity;
        }
        void setAutoDetectNebulosity(bool enable)
        {
            m_autoDetectNebulosity = enable;
            m_autoDetectNebulositySet = true;
        }
        bool isAutoDetectNebulositySet() const
        {
            return m_autoDetectNebulositySet;
        }

        float getNebulosityThreshold() const
        {
            return m_nebulosityThreshold;
        }
        void setNebulosityThreshold(float threshold)
        {
            m_nebulosityThreshold = std::max(0.0f, std::min(1.0f, threshold));
            m_nebulosityThresholdSet = true;
        }
        bool isNebulosityThresholdSet() const
        {
            return m_nebulosityThresholdSet;
        }

        // Cached nebulosity detection results
        bool hasNebulosityBeenChecked() const
        {
            return m_nebulosityChecked;
        }
        bool hasExtensiveNebulosity() const
        {
            return m_nebulosityDetected;
        }
        float getNebulosityScore() const
        {
            return m_nebulosityScore;
        }
        void setNebulosityResults(bool checked, bool detected, float score)
        {
            m_nebulosityChecked = checked;
            m_nebulosityDetected = detected;
            m_nebulosityScore = score;
        }

    private:
        // Stacking parameters
        bool m_alignFrames;
        int m_maxAlignmentStars;
        float m_backgroundAdjustment;
        float m_contrastAdjustment;
        float m_saturationAdjustment;
        float m_compressionPercentage;
        int m_medianFilterSize;
        int m_sigmaClippingFrames;
        float m_sigmaClippingLower;
        float m_sigmaClippingUpper;

        // Frame quality and diagnostic parameters
        bool m_diagnosticMode;
        std::string m_outputPrefix;
        float m_qualityThreshold;

        // Local histogram equalization parameters
        int m_localHistEqWindowSize;
        float m_localHistEqClipLimit;

        // Output and performance settings
        bool m_verboseMode;
        bool m_benchmarkMode;

        // Denoising settings
        DenoisingMethod m_denoisingMethod;
        int m_denoisingStrength;

        // Nebulosity detection settings
        bool m_autoDetectNebulosity;
        float m_nebulosityThreshold;

        // Cached nebulosity detection results
        bool m_nebulosityChecked = false;
        bool m_nebulosityDetected = false;
        float m_nebulosityScore = 0.0f;

        // Flags to track which parameters have been explicitly set
        bool m_backgroundAdjustmentSet;
        bool m_contrastAdjustmentSet;
        bool m_saturationAdjustmentSet;
        bool m_compressionPercentageSet;
        bool m_medianFilterSizeSet;
        bool m_localHistEqSet;
        bool m_denoisingSet;
        bool m_autoDetectNebulositySet;
        bool m_nebulosityThresholdSet;
};

#endif // STACKER_SETTINGS_H
