(*─────────────────────────────────────────────────────────────────────────────┐
│ SPDX-FileCopyrightText: 2021–2026 toastal <https://toast.al/contact/>        │
│ SPDX-License-Identifier: MPL-2.0                                             │
└─────────────────────────────────────────────────────────────────────────────*)
(* Custom style schema: https://github.com/alecthomas/chroma                    *)
(* Chroma styles are flat XML tokens — no pygments dotted names.                *)
open Colorscheme

let chroma_rules : (string * theme) list =
	let c = colorscheme in
	[
		("Other", c.normal);
		("Text", c.normal);
		("Comment", c.comment);
		("CommentPreproc", c.pre_proc);
		("CommentSpecial", c.special_comment);
		("Error", c.error);
		("GenericHeading", c.title);
		("GenericDeleted", c.diff_delete);
		("GenericInserted", c.diff_add);
		("Keyword", c.keyword);
		("LiteralNumber", c.number);
		("LiteralString", c.string);
		("LiteralStringEscape", c.special_char);
		("Name", c.identifier);
		("NameBuiltin", c.special);
		("NameClass", c.structure);
		("NameConstant", c.constant);
		("NameException", c.exception');
		("NameFunction", c.function');
		("NameTag", c.tag);
		("Operator", c.operator);
	]

let pp_banner (ppf : Format.formatter) () : unit =
	Fmt.pf ppf {|<!--@.|};
	Fmt.pf ppf {|SPDX-FileCopyrightText: 2021–2026 toastal <https://toast.al/contact/>@.|};
	Fmt.pf ppf {|SPDX-License-Identifier: MPL-2.0@.@.|};
	Fmt.pf ppf {|sugilite256, an 8-bit color scheme wiþ extra purple@.|};
	Fmt.pf ppf {|Support ð project: https://toast.al/funding@.|};
	Fmt.pf ppf {|-->@.|}

let pp_entry (ppf : Format.formatter) ((attr, hl): string * Highlight.t) : unit =
	let style_to_style = function
		| Bold -> Some "bold"
		| Italic -> Some "italic"
		| Underline | StrikeThrough | Undercurl -> Some "underline"
		| _ -> None
	in
	let styles : string list =
		List.concat
			[
				List.filter_map style_to_style (Styles.to_list hl.style);
				Option.to_list (Option.map (fun c -> "bg:" ^ Xterm_colors.hex_string_of_unit8 c) hl.bg);
				Option.to_list (Option.map (fun c -> Xterm_colors.hex_string_of_unit8 c) hl.fg);
			]
	in
	if styles = [] then
			()
	else
		let style = String.concat " " styles in
		Fmt.pf ppf {|	<entry type="%s" style="%s"/>@.|} attr style

let pp_style (ppf : Format.formatter) (theme_name : theme_name) : unit =
	Fmt.set_utf_8 ppf true;
	let (name, counterpart, background, tname) =
		match theme_name with
		| Dark -> ("sugilite256-dark", "sugilite256-light", "#000000", (fun (t : theme) -> t.dark))
		| Light -> ("sugilite256-light", "sugilite256-dark", "#ffffff", (fun (t : theme) -> t.light))
	in
	pp_banner ppf ();
	Fmt.pf ppf "@[<v><style name=%S counterpart=%S>@." name counterpart;
	Fmt.pf ppf {|	<entry type="Background" style="bg:%s"/>@.|} background;
	let pp_rules (attr, t) =
		pp_entry ppf (attr, tname t)
	in
	List.iter pp_rules chroma_rules;
	Fmt.pf ppf "</style>@."
