using System.Numerics;
using ILGPU;
using ILGPU.Runtime;

namespace SDFMapCreator;

public partial class SdfKernels {
    private static void SelfMaskKernel(Index2D index, ArrayView2D<Vector3, Stride2D.DenseX> input, ArrayView2D<Vector3, Stride2D.DenseX> mask) {
        int x = index.X;
        int y = index.Y;
        Vector3 value = input[x, y];
        float lumaA = (value.X + value.Y + value.Z)/3f;
        float r = lumaA > 0.99f ? 1f : 0f;
        mask[x,y] = new (r, 0f, 0f);
    }

    private static void ABMaskKernel(Index2D index,
        ArrayView2D<Vector3, Stride2D.DenseX> A,
        ArrayView2D<Vector3, Stride2D.DenseX> B,
        ArrayView2D<Vector3, Stride2D.DenseX> mask
    ) {
        int x = index.X;
        int y = index.Y;
        Vector3 valueA = A[x, y];
        Vector3 valueB = B[x, y];
        float lumaA = (valueA.X + valueA.Y + valueA.Z) / 3f;
        float lumaB = (valueB.X + valueB.Y + valueB.Z) / 3f;
        float r = lumaA > 0.99f && lumaB > 0.99f ? 1f : 0f;
        mask[x, y] = new (r, 0f, 0f);
    }

    private static void EdgeKernel(Index2D index,
        ArrayView2D<Vector3, Stride2D.DenseX> mask,
        uint width, uint height
    ) { // early exit if not on mask
       if (mask[index].X == 0f) return;
       int x = index.X;
       int y = index.Y;
       //if we are on the edge of the image, return false
       if (x == 0 || y == 0 || x == width - 1 || y == height - 1) return;
       
       //check the 3x3 kernel
       for (int xi = x - 1; xi <= x + 1; xi++) {
           for (int yi = y - 1; yi <= y + 1; yi++) {
               if (xi < 0 || xi >= width || yi < 0 || yi >= height)
                   continue; //skip out of bounds pixels
               if (mask[xi, yi].X == 0f)
                   mask[index].Y = 1f; //if we find a black pixel, return true
           }
       }
    }

    private static void SdfKernel(Index2D index,
        ArrayView2D<Vector3, Stride2D.DenseX> sdf,
        ArrayView1D<Vector2, Stride1D.Dense> edges,
        int width, int height
    ) {
        Vector2 pos = new((float)index.X / width, (float)index.Y / height);
        float minDist = 2f;
        int count = edges.IntExtent.Size;
        
        for (int i = 0; i < count; i++) {
            Vector2 edgeNrm = new (edges[i].X/width, edges[i].Y/height);
            float dist = Vector2.Distance(pos, edgeNrm);
            if (dist < minDist) minDist = dist;
        }

        if (minDist > 1f) minDist = 1f;
       
        sdf[index] = new(minDist);
    }
    
}