using System.Runtime.Versioning;
using RioJoy.Core.Editing;

namespace RioJoy.Tray.Editor;

/// <summary>
/// Draws the cockpit control panel — the functional groups from
/// <see cref="CockpitPanel"/> (MFD clusters, board columns, keypads) plus the
/// encoder-gauge strip — mirroring the original Win32 RIO design. Lamp buttons are
/// shaded by whether the address is assigned (Off vs Dim); keypads are neutral
/// (no lamps). Shared by <see cref="PanelCanvas"/> and offline rendering.
/// </summary>
[SupportedOSPlatform("windows")]
public static class PanelView
{
    public const int CellW = 66;
    public const int CellH = 34;
    public const int TopStrip = 92; // encoder-gauge band height

    public static Size GridSize(IReadOnlyList<PanelButton> buttons)
    {
        int maxCol = 0, maxRow = 0;
        foreach (PanelButton b in buttons)
        {
            if (b.Col > maxCol) maxCol = b.Col;
            if (b.Row > maxRow) maxRow = b.Row;
        }
        return new Size((maxCol + 2) * CellW, TopStrip + (maxRow + 2) * CellH);
    }

    private static Rectangle Cell(int col, int row) =>
        new(col * CellW + 2, TopStrip + row * CellH + 2, CellW - 4, CellH - 4);

    public static void Paint(
        Graphics g,
        IReadOnlyList<PanelButton> buttons,
        IReadOnlyList<PanelGroup> groups,
        Func<int, string?> label,
        Func<int, string?> function,
        Func<int, bool> lit,
        int? selected)
    {
        g.Clear(Color.FromArgb(28, 28, 28));
        using var titleFont = new Font("Segoe UI", 8f, FontStyle.Bold);
        using var btnFont = new Font("Segoe UI", 7.5f);
        using var subFont = new Font("Segoe UI", 6.75f);
        using var groupPen = new Pen(Color.FromArgb(80, 80, 80));

        DrawEncoderStrip(g, titleFont);

        // Group frames + titles.
        foreach (PanelGroup grp in groups)
        {
            var frame = new Rectangle(
                grp.OriginCol * CellW + 1,
                TopStrip + grp.OriginRow * CellH + 1,
                grp.Cols * CellW,
                (grp.Rows + 1) * CellH);
            g.DrawRectangle(groupPen, frame);
            TextRenderer.DrawText(g, grp.Title, titleFont,
                new Rectangle(frame.X + 2, frame.Y, frame.Width - 2, CellH), Color.Gainsboro,
                TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
        }

        // Buttons: caption = label (top) + assigned function (bottom).
        const TextFormatFlags oneLine = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter |
                                        TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix;
        foreach (PanelButton b in buttons)
        {
            Rectangle r = Cell(b.Col, b.Row);
            string? lab = label(b.Address);
            string? fn = function(b.Address);
            bool assigned = !string.IsNullOrEmpty(fn);

            Color fill = !b.LampCapable
                ? Color.FromArgb(150, 182, 226)                       // keypad — neutral blue
                : lit(b.Address)
                    ? Color.FromArgb(215, 60, 60)                     // lamp ON  (IsLit checked)
                    : Color.FromArgb(86, 48, 48);                     // lamp OFF
            using (var fb = new SolidBrush(fill)) g.FillRectangle(fb, r);

            Color fg = b.LampCapable ? Color.White : Color.Black;
            bool hasLab = !string.IsNullOrEmpty(lab);

            if (hasLab && assigned)
            {
                TextRenderer.DrawText(g, lab, btnFont, new Rectangle(r.X, r.Y + 1, r.Width, r.Height / 2), fg,
                    TextFormatFlags.HorizontalCenter | TextFormatFlags.Top | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix);
                TextRenderer.DrawText(g, fn, subFont, new Rectangle(r.X, r.Bottom - r.Height / 2 - 1, r.Width, r.Height / 2), fg,
                    TextFormatFlags.HorizontalCenter | TextFormatFlags.Bottom | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix);
            }
            else
            {
                string single = hasLab ? lab! : assigned ? fn! : $"{b.Address:X2}";
                TextRenderer.DrawText(g, single, btnFont, r, fg, oneLine);
            }

            if (b.Address == selected)
            {
                using var hi = new Pen(Color.Yellow, 2f);
                g.DrawRectangle(hi, r.X, r.Y, r.Width - 1, r.Height - 1);
            }
        }
    }

    private static void DrawEncoderStrip(Graphics g, Font font)
    {
        using var pen = new Pen(Color.FromArgb(120, 160, 120));
        using var gauge = new SolidBrush(Color.FromArgb(20, 40, 20));

        (string Label, int X, int W)[] boxes =
        {
            ("X / Y", 4, 80),
            ("Z", 92, 26),
            ("L", 122, 26),
            ("R", 152, 26),
        };
        foreach (var (lbl, x, w) in boxes)
        {
            var r = new Rectangle(x, 6, w, TopStrip - 24);
            g.FillRectangle(gauge, r);
            g.DrawRectangle(pen, r);
            TextRenderer.DrawText(g, lbl, font, new Rectangle(x, TopStrip - 18, w, 16), Color.Gainsboro,
                TextFormatFlags.HorizontalCenter);
        }
    }

    public static PanelButton? HitTest(IReadOnlyList<PanelButton> buttons, Point p)
    {
        foreach (PanelButton b in buttons)
            if (Cell(b.Col, b.Row).Contains(p))
                return b;
        return null;
    }
}
