using System;
using System.Runtime.InteropServices;

/// Form2.AnalyzeColorScheme, ported to Gdk.Pixbuf.
public static class MapAudio
{
    public const int MIN_INTENSITY               = 50;
    public const int DOMINANCE_THRESHOLD         = 30;
    public const int MIN_PURITY                  = 40;
    public const int BLACK_THRESHOLD             = 40;
    public const int BLACK_PIXEL_CONSTANT_VOLUME = 51;   // 20% of 255

    public enum Region { None, Black, Red, Blue }

    public class Result
    {
        public Region Region;
        public bool   Play;
        public int    Level;        // 0..255, feeds AudioEngine.VolumeCurve
        public byte   R, G, B, A;
    }

    /// Reads one pixel out of a pixbuf. False if out of bounds.
    public static bool ReadPixel(Gdk.Pixbuf pb, int x, int y,
                                 out byte r, out byte g, out byte b, out byte a)
    {
        r = g = b = 0; a = 255;
        if (pb == null) return false;
        if (x < 0 || y < 0 || x >= pb.Width || y >= pb.Height) return false;

        int n = pb.NChannels;
        IntPtr p = pb.Pixels + y * pb.Rowstride + x * n;

        r = Marshal.ReadByte(p, 0);
        g = Marshal.ReadByte(p, 1);
        b = Marshal.ReadByte(p, 2);
        a = (n >= 4) ? Marshal.ReadByte(p, 3) : (byte)255;
        return true;
    }

    public static Result Analyze(Gdk.Pixbuf map, int px, int py, bool blackAudioEnabled)
    {
        var res = new Result { Region = Region.None, Play = false, Level = 0 };

        byte r, g, b, a;
        if (!ReadPixel(map, px, py, out r, out g, out b, out a))
            return res;

        res.R = r; res.G = g; res.B = b; res.A = a;

        int max    = Math.Max(Math.Max(r, g), b);
        int min    = Math.Min(Math.Min(r, g), b);
        int purity = max - min;

        // LoadMap keys out black with AddAlpha, so background arrives as
        // alpha 0, not RGB(0,0,0). This test has to come first or every
        // background hit reads as a valid colour.
        bool isBackground = a < 128 || max < BLACK_THRESHOLD;

        if (isBackground)
        {
            res.Region = Region.Black;
            if (blackAudioEnabled)
            {
                res.Play  = true;
                res.Level = BLACK_PIXEL_CONSTANT_VOLUME;
            }
            return res;
        }

        // RED — heart territory
        if (r >= MIN_INTENSITY &&
            r > g + DOMINANCE_THRESHOLD &&
            r > b + DOMINANCE_THRESHOLD &&
            purity >= MIN_PURITY)
        {
            res.Region = Region.Red;
            res.Play   = true;
            res.Level  = LevelFrom(r);
            return res;
        }

        // BLUE — breath territory
        if (b >= MIN_INTENSITY &&
            b > r + DOMINANCE_THRESHOLD &&
            b > g + DOMINANCE_THRESHOLD &&
            purity >= MIN_PURITY)
        {
            res.Region = Region.Blue;
            res.Play   = true;
            res.Level  = LevelFrom(b);
            return res;
        }

        return res;   // unassigned colour -> silence
    }

    /// Form2: intensity 50..255 maps to volume level 80..255.
    private static int LevelFrom(int intensity)
    {
        float t = (intensity - MIN_INTENSITY) / (255.0f - MIN_INTENSITY);
        int level = (int)(80 + t * 175);
        return Math.Max(80, Math.Min(255, level));
    }
}