"""Draw a rounded border around any widget with a Cairo DrawingArea overlay.

This GTK build's renderer does not paint CSS border/background nodes on plain
container widgets (Box/Frame) — only on buttons/entries — but it renders Cairo
draw funcs and textures fine (the map image proves it). So module 'borders' are
drawn explicitly here instead of via CSS.
"""

from __future__ import annotations

import math

import gi

gi.require_version("Gtk", "4.0")
from gi.repository import Gtk  # noqa: E402

# CyberQueer accent (matches @accent / COLOR_HIGHLIGHT in colors.conf).
ACCENT = (0xE4 / 255, 0x00 / 255, 0x46 / 255)
BG = (0x1A / 255, 0x1A / 255, 0x1A / 255)


def _rounded_rect(cr, x, y, w, h, r) -> None:
    r = min(r, w / 2, h / 2)
    cr.new_sub_path()
    cr.arc(x + w - r, y + r, r, -math.pi / 2, 0)
    cr.arc(x + w - r, y + h - r, r, 0, math.pi / 2)
    cr.arc(x + r, y + h - r, r, math.pi / 2, math.pi)
    cr.arc(x + r, y + r, r, math.pi, 3 * math.pi / 2)
    cr.close_path()


def _make_draw(border: int, radius: int, color, fill_bg: bool):
    def draw(_area, cr, w, h, *_a) -> None:
        inset = border / 2
        _rounded_rect(cr, inset, inset, w - border, h - border, radius)
        if fill_bg:
            cr.set_source_rgb(*BG)
            cr.fill_preserve()
        cr.set_source_rgb(*color)
        cr.set_line_width(border)
        cr.stroke()
    return draw


def bordered(child: Gtk.Widget, border: int = 3, radius: int = 16,
             color=ACCENT, fill_bg: bool = False) -> Gtk.Overlay:
    """Wrap child in an overlay whose background is a drawn rounded border.

    The DrawingArea is the overlay's main child (drawn first, behind); the content
    is an overlay child on top and drives the size. A small margin keeps the content
    clear of the drawn border ring.
    """
    overlay = Gtk.Overlay()
    area = Gtk.DrawingArea()
    area.set_draw_func(_make_draw(border, radius, color, fill_bg))
    overlay.set_child(area)               # background: the border ring
    child.set_margin_start(border + 4)
    child.set_margin_end(border + 4)
    child.set_margin_top(border + 4)
    child.set_margin_bottom(border + 4)
    overlay.add_overlay(child)            # content on top
    overlay.set_measure_overlay(child, True)  # size the overlay to the content
    return overlay
