#ifndef BACKGROUNDEXTRACTOR_H
#define BACKGROUNDEXTRACTOR_H

#include <memory>
#include <vector>
#include <opencv2/opencv.hpp>
#include <gsl/gsl_multifit.h>
#include "../buffer/imagebuffer.h"

/**
 * @brief The BackgroundExtractor class handles automatic background extraction for astronomical images.
 *
 * This class provides functionality for removing background gradients from astronomical images
 * while preserving faint objects and nebulosity.
 */
class BackgroundExtractor
{
    public:
        /**
         * @brief Construct a new BackgroundExtractor object
         */
        BackgroundExtractor();

        /**
         * @brief Destroy the BackgroundExtractor object
         */
        ~BackgroundExtractor();

        /**
         * @brief Set the polynomial degree for background modeling
         * @param degree The polynomial degree (1-4, default: 2)
         */
        void setPolynomialDegree(int degree);

        /**
         * @brief Set the sample grid size
         * @param gridSize The grid size (8-64, default: 16)
         */
        void setSampleGridSize(int gridSize);

        /**
         * @brief Set the protection threshold for nebulae and faint objects
         * @param threshold The protection threshold (0.0-1.0, default: 0.5)
         */
        void setProtectionThreshold(float threshold);

        /**
         * @brief Set the smoothness factor for the background model
         * @param smoothness The smoothness factor (0.0-1.0, default: 0.5)
         */
        void setSmoothnessFactor(float smoothness);

        /**
         * @brief Process an image to remove background gradients
         * @param image The input image
         * @return The processed image with background gradients removed
         */
        template <typename T>
        std::shared_ptr<ImageBuffer<T>> process(const std::shared_ptr<ImageBuffer<T>> &image);

        /**
         * @brief Generate a preview of the background model
         * @param image The input image
         * @return The background model as an image
         */
        template <typename T>
        std::shared_ptr<ImageBuffer<T>> generateBackgroundModel(const std::shared_ptr<ImageBuffer<T>> &image);

    private:
        /**
         * @brief Detect stars and other bright objects in an image
         * @param image The input image
         * @return A mask where non-zero pixels represent detected objects
         */
        cv::Mat detectObjects(const cv::Mat &image);


        /**
         * @brief Detect stars using OpenCV
         * @param image The input image
         * @return A mask where non-zero pixels represent detected stars
         */
        cv::Mat detectStarsWithOpenCV(const cv::Mat &image);

        /**
         * @brief Create a protection mask for nebulae and faint objects
         * @param image The input image
         * @return A mask where non-zero pixels represent protected areas
         */
        cv::Mat createProtectionMask(const cv::Mat &image);

        /**
         * @brief Sample background points from an image
         * @param image The input image
         * @param mask The mask where non-zero pixels should be excluded from sampling
         * @return A vector of sample points (x, y, value)
         */
        std::vector<cv::Point3f> sampleBackgroundPoints(const cv::Mat &image, const cv::Mat &mask);

        /**
         * @brief Fit a polynomial surface to the background points
         * @param points The background sample points
         * @param width The width of the image
         * @param height The height of the image
         * @return The coefficients of the polynomial surface
         */
        std::vector<double> fitPolynomialSurface(const std::vector<cv::Point3f> &points, int width, int height);

        /**
         * @brief Generate a background model from polynomial coefficients
         * @param coefficients The polynomial coefficients
         * @param width The width of the image
         * @param height The height of the image
         * @return The background model as an image
         */
        cv::Mat generateBackgroundModelFromCoefficients(const std::vector<double> &coefficients, int width, int height);

        /**
         * @brief Apply the background model to an image
         * @param image The input image
         * @param backgroundModel The background model
         * @return The processed image with background gradients removed
         */
        cv::Mat applyBackgroundModel(const cv::Mat &image, const cv::Mat &backgroundModel);

        /**
         * @brief Convert an ImageBuffer to an OpenCV Mat
         * @param image The input ImageBuffer
         * @return The converted OpenCV Mat
         */
        template <typename T>
        cv::Mat imageBufferToMat(const std::shared_ptr<ImageBuffer<T>> &image);

        /**
         * @brief Convert an OpenCV Mat to an ImageBuffer
         * @param mat The input OpenCV Mat
         * @return The converted ImageBuffer
         */
        template <typename T>
        std::shared_ptr<ImageBuffer<T>> matToImageBuffer(const cv::Mat &mat);

    private:
        int m_polynomialDegree;
        int m_sampleGridSize;
        float m_protectionThreshold;
        float m_smoothnessFactor;
};

// Include the template implementation
#include "backgroundextractor.tpp"

#endif // BACKGROUNDEXTRACTOR_H
