using NLog.Filters;
using OpenCvSharp;

namespace Hawkeye.VisionBuilder.UI.Sources.Hawkeye;

public class OpenCVBayerProcessor
{
    private SplineInterpolator GreenInterpolation { get; set; }
    private SplineInterpolator RedInterpolation { get; set; }
    private SplineInterpolator BlueInterpolation { get; set; }

    // Cached lookup tables
    private byte[] redLut;
    private byte[] greenLut;
    private byte[] blueLut;
    private Mat _lookupTable;

    public OpenCVBayerProcessor()
    {
        // Initialize with default linear interpolation (same as your defaults)
        GreenInterpolation = new SplineInterpolator(new Dictionary<double, double>()
            {{0,0}, { 100, 100 }, { 255,255}});
        RedInterpolation = new SplineInterpolator(new Dictionary<double, double>()
            {{0,0}, { 100, 100 }, { 255,255}});
        BlueInterpolation = new SplineInterpolator(new Dictionary<double, double>()
            {{0,0}, { 100, 100 }, { 255,255}});

        UpdateLookupTables();
    }

    public void SetInterpolators(SplineInterpolator red, SplineInterpolator green, SplineInterpolator blue)
    {
        RedInterpolation = red;
        GreenInterpolation = green;
        BlueInterpolation = blue;
        UpdateLookupTables();
    }

    public void SetCalibration(List<Dictionary<double, double>> calibration)
    {
        RedInterpolation = new SplineInterpolator(calibration[0]);
        GreenInterpolation = new SplineInterpolator(calibration[1]);
        BlueInterpolation = new SplineInterpolator(calibration[2]);
        UpdateLookupTables();
    }

    private void UpdateLookupTables()
    {
        redLut = Enumerable.Range(0, 256).Select(x => (byte)RedInterpolation.GetValue(x)).ToArray();
        greenLut = Enumerable.Range(0, 256).Select(x => (byte)GreenInterpolation.GetValue(x)).ToArray();
        blueLut = Enumerable.Range(0, 256).Select(x => (byte)BlueInterpolation.GetValue(x)).ToArray();

        // Create lookup table for all three channels
        _lookupTable = new Mat(1, 256, MatType.CV_8UC3);

        // Use the Mat indexer for safe access
        var indexer = _lookupTable.GetGenericIndexer<Vec3b>();
        for (int i = 0; i < 256; i++)
        {
            indexer[0, i] = new Vec3b(blueLut[i], greenLut[i], redLut[i]);
        }
    }

    public Mat ProcessBayerImage(Mat grayImage)
    {
        // Step 1: Apply Bayer demosaicing with RG pattern (matching your pattern)
        Mat colorImage = new Mat();
        Cv2.CvtColor(grayImage, colorImage, ColorConversionCodes.BayerBG2BGR);

        // Step 2: Apply color interpolation/correction using lookup tables
        Mat correctedImage = ApplyColorCorrection(colorImage);

        return correctedImage;
    }

    private Mat ApplyColorCorrection(Mat colorImage)
    {
       

        // Apply the lookup table
        Mat result = new Mat();
        Cv2.LUT(colorImage, _lookupTable, result);

        
        return result;
    }

    // Alternative: Apply correction per channel if you need more control
    public Mat ProcessBayerImageWithChannelControl(Mat grayImage)
    {
        // Step 1: Demosaic
        Mat colorImage = new Mat();
        Cv2.CvtColor(grayImage, colorImage, ColorConversionCodes.BayerBG2BGR);

        // Step 2: Split channels
        Mat[] channels = Cv2.Split(colorImage);

        // Step 3: Apply individual LUTs to each channel
        Mat blueCorrected = new Mat();
        Mat greenCorrected = new Mat();
        Mat redCorrected = new Mat();

        Mat blueLutMat = Mat.FromPixelData(1, 256, MatType.CV_8U, blueLut);
        Mat greenLutMat = Mat.FromPixelData(1, 256, MatType.CV_8U, greenLut);
        Mat redLutMat = Mat.FromPixelData(1, 256, MatType.CV_8U, redLut);

        Cv2.LUT(channels[0], blueLutMat, blueCorrected);
        Cv2.LUT(channels[1], greenLutMat, greenCorrected);
        Cv2.LUT(channels[2], redLutMat, redCorrected);

        // Step 4: Merge channels back
        Mat result = new Mat();
        Cv2.Merge(new Mat[] { blueCorrected, greenCorrected, redCorrected }, result);

        // Cleanup
        foreach (var channel in channels) channel.Dispose();
        blueCorrected.Dispose();
        greenCorrected.Dispose();
        redCorrected.Dispose();
        colorImage.Dispose();

        return result;
    }
}