///|
fn is_dom_bool_property(attr_name : String) -> Bool {
  attr_name
  is ("checked"
  | "disabled"
  | "hidden"
  | "selected"
  | "multiple"
  | "autofocus"
  | "required"
  | "readonly"
  | "open"
  | "async"
  | "defer"
  | "loop"
  | "muted"
  | "controls"
  | "autoplay"
  | "allowfullscreen"
  | "playsinline"
  | "inert"
  | "novalidate"
  | "formnovalidate"
  | "ismap"
  | "default")
}

///|
fn is_dom_string_property(attr_name : String) -> Bool {
  attr_name is ("value" | "href" | "textContent")
}

///|
priv enum AttrParamType {
  AttrString
  AttrBool
  AttrInt
}

///|
priv struct AttrMethodInfo {
  method_name : String
  param_type : AttrParamType
}

///|
let attrs_method_registry : Map[String, AttrMethodInfo] = {
  "accept": { method_name: "accept", param_type: AttrString },
  "accept-charset": { method_name: "accept_charset", param_type: AttrString },
  "accesskey": { method_name: "accesskey", param_type: AttrString },
  "action": { method_name: "action", param_type: AttrString },
  "align": { method_name: "align", param_type: AttrString },
  "allow": { method_name: "allow", param_type: AttrString },
  "alt": { method_name: "alt", param_type: AttrString },
  "async": { method_name: "async_", param_type: AttrBool },
  "autocapitalize": { method_name: "autocapitalize", param_type: AttrString },
  "autocomplete": { method_name: "autocomplete", param_type: AttrString },
  "autofocus": { method_name: "autofocus", param_type: AttrBool },
  "autoplay": { method_name: "autoplay", param_type: AttrBool },
  "bgcolor": { method_name: "bgcolor", param_type: AttrString },
  "border": { method_name: "border", param_type: AttrInt },
  "charset": { method_name: "charset", param_type: AttrString },
  "checked": { method_name: "checked", param_type: AttrBool },
  "cite": { method_name: "cite", param_type: AttrString },
  "class": { method_name: "class", param_type: AttrString },
  "color": { method_name: "color", param_type: AttrString },
  "cols": { method_name: "cols", param_type: AttrInt },
  "colspan": { method_name: "colspan", param_type: AttrInt },
  "content": { method_name: "content", param_type: AttrString },
  "contenteditable": { method_name: "contenteditable", param_type: AttrString },
  "controls": { method_name: "controls", param_type: AttrBool },
  "coords": { method_name: "coords", param_type: AttrString },
  "crossorigin": { method_name: "crossorigin", param_type: AttrString },
  "data": { method_name: "data", param_type: AttrString },
  "datetime": { method_name: "datetime", param_type: AttrString },
  "decoding": { method_name: "decoding", param_type: AttrString },
  "default": { method_name: "default", param_type: AttrBool },
  "defer": { method_name: "defer_", param_type: AttrBool },
  "dir": { method_name: "dir", param_type: AttrString },
  "dirname": { method_name: "dirname", param_type: AttrString },
  "disabled": { method_name: "disabled", param_type: AttrBool },
  "download": { method_name: "download", param_type: AttrString },
  "draggable": { method_name: "draggable", param_type: AttrString },
  "enctype": { method_name: "enctype", param_type: AttrString },
  "for": { method_name: "for_", param_type: AttrString },
  "form": { method_name: "form", param_type: AttrString },
  "formaction": { method_name: "formaction", param_type: AttrString },
  "formenctype": { method_name: "formenctype", param_type: AttrString },
  "formmethod": { method_name: "formmethod", param_type: AttrString },
  "formnovalidate": { method_name: "formnovalidate", param_type: AttrBool },
  "formtarget": { method_name: "formtarget", param_type: AttrString },
  "headers": { method_name: "headers", param_type: AttrString },
  "height": { method_name: "height", param_type: AttrInt },
  "hidden": { method_name: "hidden", param_type: AttrBool },
  "high": { method_name: "high", param_type: AttrInt },
  "href": { method_name: "href", param_type: AttrString },
  "hreflang": { method_name: "hreflang", param_type: AttrString },
  "http-equiv": { method_name: "http_equiv", param_type: AttrString },
  "id": { method_name: "id", param_type: AttrString },
  "inert": { method_name: "inert", param_type: AttrBool },
  "inputmode": { method_name: "inputmode", param_type: AttrString },
  "ismap": { method_name: "ismap", param_type: AttrBool },
  "kind": { method_name: "kind", param_type: AttrString },
  "label": { method_name: "label", param_type: AttrString },
  "lang": { method_name: "lang", param_type: AttrString },
  "loading": { method_name: "loading", param_type: AttrString },
  "list": { method_name: "list", param_type: AttrString },
  "loop": { method_name: "loop_", param_type: AttrBool },
  "low": { method_name: "low", param_type: AttrInt },
  "max": { method_name: "max", param_type: AttrInt },
  "maxlength": { method_name: "maxlength", param_type: AttrInt },
  "media": { method_name: "media", param_type: AttrString },
  "method": { method_name: "method_", param_type: AttrString },
  "min": { method_name: "min", param_type: AttrInt },
  "minlength": { method_name: "minlength", param_type: AttrInt },
  "multiple": { method_name: "multiple", param_type: AttrBool },
  "muted": { method_name: "muted", param_type: AttrBool },
  "name": { method_name: "name", param_type: AttrString },
  "novalidate": { method_name: "novalidate", param_type: AttrBool },
  "open": { method_name: "open", param_type: AttrBool },
  "optimum": { method_name: "optimum", param_type: AttrInt },
  "pattern": { method_name: "pattern", param_type: AttrString },
  "placeholder": { method_name: "placeholder", param_type: AttrString },
  "playsinline": { method_name: "playsinline", param_type: AttrBool },
  "poster": { method_name: "poster", param_type: AttrString },
  "preload": { method_name: "preload", param_type: AttrString },
  "readonly": { method_name: "readonly_", param_type: AttrBool },
  "rel": { method_name: "rel", param_type: AttrString },
  "required": { method_name: "required", param_type: AttrBool },
  "reversed": { method_name: "reversed", param_type: AttrBool },
  "role": { method_name: "role", param_type: AttrString },
  "rows": { method_name: "rows", param_type: AttrInt },
  "rowspan": { method_name: "rowspan", param_type: AttrInt },
  "sandbox": { method_name: "sandbox", param_type: AttrString },
  "shape": { method_name: "shape", param_type: AttrString },
  "size": { method_name: "size", param_type: AttrInt },
  "sizes": { method_name: "sizes", param_type: AttrString },
  "span": { method_name: "span", param_type: AttrInt },
  "src": { method_name: "src", param_type: AttrString },
  "srcdoc": { method_name: "srcdoc", param_type: AttrString },
  "srclang": { method_name: "srclang", param_type: AttrString },
  "srcset": { method_name: "srcset", param_type: AttrString },
  "start": { method_name: "start", param_type: AttrInt },
  "step": { method_name: "step", param_type: AttrInt },
  "style": { method_name: "style_attr", param_type: AttrString },
  "tabindex": { method_name: "tabindex", param_type: AttrInt },
  "target": { method_name: "target", param_type: AttrString },
  "title": { method_name: "title", param_type: AttrString },
  "type": { method_name: "type_", param_type: AttrString },
  "value": { method_name: "value", param_type: AttrString },
  "width": { method_name: "width", param_type: AttrInt },
  "wrap": { method_name: "wrap", param_type: AttrString },
  "allowfullscreen": { method_name: "allowfullscreen", param_type: AttrBool },
  "colspan": { method_name: "colspan", param_type: AttrInt },
  "selected": { method_name: "selected", param_type: AttrBool },
}

///|
fn get_attr_method(attr_name : String) -> AttrMethodInfo? {
  attrs_method_registry.get(attr_name)
}

///|
priv struct StyleDecl {
  prop : String
  value : String
}

///|
fn parse_style(style_str : String) -> Array[StyleDecl] {
  style_str
  .split(";")
  .filter_map(part => {
    let trimmed = part.trim()
    if trimmed.is_empty() {
      return None
    }
    trimmed
    .split_once(":")
    .bind(pair => {
      let (prop, value) = pair
      if prop.is_empty() {
        None
      } else {
        Some({ prop: prop.to_string(), value: value.trim().to_string() })
      }
    })
  })
  .collect()
}

///|
priv enum AttrKind {
  CommonNamedParam(String)
  TagSpecificNamedParam(String)
  DomBoolProperty
  DomStringProperty
  StyleAttr
  FallbackAttribute
  EventHandler
}

///|
fn classify_attr(
  attr_name : String,
  tag : String,
  tag_params : Map[String, String],
) -> AttrKind {
  ignore(tag)
  if attr_name == "style" {
    return StyleAttr
  }
  if tag_params.contains(attr_name) {
    return TagSpecificNamedParam(tag_params[attr_name])
  }
  match attr_name {
    "id" => CommonNamedParam("id")
    "class" => CommonNamedParam("class")
    "title" => CommonNamedParam("title")
    "hidden" => CommonNamedParam("hidden")
    _ =>
      if is_dom_bool_property(attr_name) {
        DomBoolProperty
      } else if is_dom_string_property(attr_name) {
        DomStringProperty
      } else if attr_name.has_prefix("on") {
        EventHandler
      } else {
        FallbackAttribute
      }
  }
}