// HTML/Attribute/JS String Escaping Utilities
//
// Luna-specific JSON escaping functions are defined here.

///|
/// Check if string needs HTML escaping
pub fn needs_html_escape(s : String) -> Bool {
  s
  .iter()
  .any(fn(c) { c == '&' || c == '<' || c == '>' || c == '"' || c == '\'' })
}

///|
/// Escape HTML special characters and write to StringBuilder
pub fn escape_html_to(sb : StringBuilder, s : String) -> Unit {
  escape_html_view_to(sb, s[:])
}

///|
fn escape_html_view_to(sb : StringBuilder, s : StringView) -> Unit {
  let len = s.length()
  for i = 0, segment_start = 0 {
    if i >= len {
      if i > segment_start {
        sb.write_view(s[segment_start:i])
      }
      break
    }
    match s.unsafe_get(i) {
      '&' => {
        if i > segment_start {
          sb.write_view(s[segment_start:i])
        }
        sb.write_string("&")
        continue i + 1, i + 1
      }
      '<' => {
        if i > segment_start {
          sb.write_view(s[segment_start:i])
        }
        sb.write_string("<")
        continue i + 1, i + 1
      }
      '>' => {
        if i > segment_start {
          sb.write_view(s[segment_start:i])
        }
        sb.write_string(">")
        continue i + 1, i + 1
      }
      '"' => {
        if i > segment_start {
          sb.write_view(s[segment_start:i])
        }
        sb.write_string(""")
        continue i + 1, i + 1
      }
      '\'' => {
        if i > segment_start {
          sb.write_view(s[segment_start:i])
        }
        sb.write_string("'")
        continue i + 1, i + 1
      }
      _ => continue i + 1, segment_start
    }
  }
}

///|
/// Escape HTML and return new string
pub fn escape_html(s : String) -> String {
  if !needs_html_escape(s) {
    return s
  }
  let sb = StringBuilder(size_hint=s.length() + 16)
  escape_html_to(sb, s)
  sb.to_string()
}

///|
/// Check if string needs attribute escaping (subset of HTML)
pub fn needs_attr_escape(s : String) -> Bool {
  s.iter().any(fn(c) { c == '&' || c == '"' })
}

///|
/// Escape attribute value and write to StringBuilder
pub fn escape_attr_to(sb : StringBuilder, s : String) -> Unit {
  escape_attr_view_to(sb, s[:])
}

///|
fn escape_attr_view_to(sb : StringBuilder, s : StringView) -> Unit {
  let len = s.length()
  for i = 0, segment_start = 0 {
    if i >= len {
      if i > segment_start {
        sb.write_view(s[segment_start:i])
      }
      break
    }
    match s.unsafe_get(i) {
      '&' => {
        if i > segment_start {
          sb.write_view(s[segment_start:i])
        }
        sb.write_string("&")
        continue i + 1, i + 1
      }
      '"' => {
        if i > segment_start {
          sb.write_view(s[segment_start:i])
        }
        sb.write_string(""")
        continue i + 1, i + 1
      }
      _ => continue i + 1, segment_start
    }
  }
}

///|
/// Escape attribute and return new string
pub fn escape_attr(s : String) -> String {
  if !needs_attr_escape(s) {
    return s
  }
  let sb = StringBuilder(size_hint=s.length() + 8)
  escape_attr_to(sb, s)
  sb.to_string()
}

///|
/// Escape JS string for embedding in script tags
/// Handles  injection prevention
pub fn escape_js_string(s : String) -> String {
  let sb = StringBuilder(size_hint=s.length() + 16)
  escape_js_string_to(sb, s)
  sb.to_string()
}

///|
/// Escape JS string and write to StringBuilder
pub fn escape_js_string_to(sb : StringBuilder, s : String) -> Unit {
  for c in s {
    match c {
      '<' => sb.write_string("\\u003c")
      '>' => sb.write_string("\\u003e")
      '\\' => sb.write_string("\\\\")
      '"' => sb.write_string("\\\"")
      '\n' => sb.write_string("\\n")
      '\r' => sb.write_string("\\r")
      '\t' => sb.write_string("\\t")
      _ => sb.write_char(c)
    }
  }
}

///|
/// Check if HTML tag is a void (self-closing) element
pub fn is_void_element(tag : String) -> Bool {
  match tag {
    "area"
    | "base"
    | "br"
    | "col"
    | "embed"
    | "hr"
    | "img"
    | "input"
    | "keygen"
    | "link"
    | "meta"
    | "param"
    | "source"
    | "track"
    | "wbr" => true
    _ => false
  }
}

// =============================================================================
// JSON Escaping for HTML embedding - Luna-specific
// =============================================================================

///|
/// Check if JSON string needs escaping for HTML attribute
fn needs_json_attr_escape(s : String) -> Bool {
  s.iter().any(fn(c) { c == '"' || c == '&' || c == '<' || c == '>' })
}

///|
/// Escape JSON for safe embedding in HTML  injection)
/// - ` `<\u0073` / `<\u0053` (additional safety)
///
/// Reference: https://sophiebits.com/2012/08/03/preventing-xss-json
pub fn escape_json_for_script(json : String) -> String {
  let chars = json.to_array()
  let len = chars.length()

  // Check if escaping is needed
  let mut needs_escape = false
  for i, c in chars {
    if c == '<' && i + 1 < len {
      let next = chars[i + 1]
      if next == '/' || next == 's' || next == 'S' {
        needs_escape = true
        break
      }
    }
  }
  if !needs_escape {
    return json
  }

  // Slow path: build escaped string
  let sb = StringBuilder(size_hint=json.length() + 16)
  let mut i = 0
  while i < len {
    let c = chars[i]
    if c == '<' && i + 1 < len {
      let next = chars[i + 1]
      if next == '/' {
        sb.write_string("<\\/")
        i = i + 2
        continue
      } else if next == 's' {
        sb.write_string("<\\u0073")
        i = i + 2
        continue
      } else if next == 'S' {
        sb.write_string("<\\u0053")
        i = i + 2
        continue
      }
    }
    sb.write_char(c)
    i = i + 1
  }
  sb.to_string()
}

///|
/// Escape JSON for safe embedding in HTML attribute values
///
/// Escapes:
/// - `"` -> `"`
/// - `&` -> `&`
/// - `<` -> `<`
/// - `>` -> `>`
pub fn escape_json_for_attr(json : String) -> String {
  if !needs_json_attr_escape(json) {
    return json
  }
  let sb = StringBuilder(size_hint=json.length() + 32)
  for c in json {
    match c {
      '"' => sb.write_string(""")
      '&' => sb.write_string("&")
      '<' => sb.write_string("<")
      '>' => sb.write_string(">")
      _ => sb.write_char(c)
    }
  }
  sb.to_string()
}