// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Spec for missing Pug features
/// This file declares the interfaces for features to be implemented

///|
/// Evaluate a simple expression with locals
/// Supports: variable lookup, string concat (+), string literals, ternary (? :)
/// Example: baseUrl + '/path' with {baseUrl: "http://example.com"}
/// Example: active ? 'on' : 'off' with {active: "true"}
pub fn eval_expression(expr : String, locals : Locals) -> String {
  let trimmed = trim_spaces(expr)
  // Check for ternary expression: condition ? true_val : false_val
  match parse_ternary(trimmed) {
    Some((cond, true_val, false_val)) => {
      let cond_result = eval_condition_simple(cond, locals)
      if cond_result {
        eval_expression(true_val, locals)
      } else {
        eval_expression(false_val, locals)
      }
    }
    None => {
      // Check for string concatenation with +
      let parts = split_on_plus(trimmed)
      if parts.length() > 1 {
        let buf = StringBuilder::new()
        for part in parts {
          buf.write_string(eval_single_expr(trim_spaces(part), locals))
        }
        buf.to_string()
      } else {
        eval_single_expr(trimmed, locals)
      }
    }
  }
}

///|
/// Parse a ternary expression: condition ? true_val : false_val
fn parse_ternary(expr : String) -> (String, String, String)? {
  let chars = expr.to_array()
  let mut question_pos = -1
  let mut colon_pos = -1
  let mut in_single_quote = false
  let mut in_double_quote = false
  // Find ? and : positions, respecting quotes
  for i, c in chars {
    if c == '\'' && not(in_double_quote) {
      in_single_quote = not(in_single_quote)
    } else if c == '"' && not(in_single_quote) {
      in_double_quote = not(in_double_quote)
    } else if c == '?' && not(in_single_quote) && not(in_double_quote) {
      question_pos = i
    } else if c == ':' &&
      not(in_single_quote) &&
      not(in_double_quote) &&
      question_pos >= 0 {
      colon_pos = i
      break // Only find the first : after ?
    }
  }
  if question_pos < 0 || colon_pos < 0 {
    return None
  }
  // Extract parts
  let cond = StringBuilder::new()
  for i in 0.. Bool {
  match locals.get(cond) {
    Some(v) => v != "" && v != "false"
    None => false
  }
}

///|
/// Trim leading and trailing spaces from a string
fn trim_spaces(s : String) -> String {
  let chars = s.to_array()
  let mut start = 0
  let mut end = chars.length()
  while start < end && chars[start] == ' ' {
    start += 1
  }
  while end > start && chars[end - 1] == ' ' {
    end -= 1
  }
  if start >= end {
    return ""
  }
  let buf = StringBuilder::new()
  for i in start.. Array[String] {
  let parts : Array[String] = []
  let buf = StringBuilder::new()
  let chars = s.to_array()
  let mut in_single_quote = false
  let mut in_double_quote = false
  let mut i = 0
  while i < chars.length() {
    let c = chars[i]
    if c == '\'' && not(in_double_quote) {
      in_single_quote = not(in_single_quote)
      buf.write_char(c)
    } else if c == '"' && not(in_single_quote) {
      in_double_quote = not(in_double_quote)
      buf.write_char(c)
    } else if c == '+' && not(in_single_quote) && not(in_double_quote) {
      parts.push(buf.to_string())
      buf.reset()
    } else {
      buf.write_char(c)
    }
    i += 1
  }
  let remaining = buf.to_string()
  if remaining.length() > 0 {
    parts.push(remaining)
  }
  parts
}

///|
/// Evaluate a single expression (variable or literal)
fn eval_single_expr(expr : String, locals : Locals) -> String {
  // Check for quoted string literal
  if expr.length() >= 2 {
    let chars = expr.to_array()
    if (chars[0] == '\'' && chars[chars.length() - 1] == '\'') ||
      (chars[0] == '"' && chars[chars.length() - 1] == '"') {
      // Strip quotes and return literal
      let inner = StringBuilder::new()
      for i in 1..<(chars.length() - 1) {
        inner.write_char(chars[i])
      }
      return inner.to_string()
    }
  }
  // Otherwise it's a variable lookup
  match locals.get(expr) {
    Some(val) => val
    None => expr // Return as-is if not found
  }
}

///|
/// Apply a filter to content
/// Supports: plain (as-is), markdown (simple conversion)
pub fn apply_filter(filter : String, content : String) -> String {
  match filter {
    "plain" => content
    "markdown" => markdown_to_html(content)
    _ => content // Unknown filter, return as-is
  }
}

///|
/// Simple markdown to HTML conversion
/// Supports: # headings, paragraphs, **bold**, *italic*
fn markdown_to_html(md : String) -> String {
  let buf = StringBuilder::new()
  let lines = md.split("\n")
  let mut in_paragraph = false
  for line in lines {
    let trimmed = line.to_string()
    if trimmed.length() == 0 {
      if in_paragraph {
        buf.write_string("

") in_paragraph = false } } else if trimmed.has_prefix("# ") { if in_paragraph { buf.write_string("

") in_paragraph = false } buf.write_string("

") buf.write_string(try! trimmed[2:].to_string()) buf.write_string("

") } else if trimmed.has_prefix("## ") { if in_paragraph { buf.write_string("

") in_paragraph = false } buf.write_string("

") buf.write_string(try! trimmed[3:].to_string()) buf.write_string("

") } else if trimmed.has_prefix("### ") { if in_paragraph { buf.write_string("

") in_paragraph = false } buf.write_string("

") buf.write_string(try! trimmed[4:].to_string()) buf.write_string("

") } else { if not(in_paragraph) { buf.write_string("

") in_paragraph = true } else { buf.write_string(" ") } buf.write_string(trimmed) } } if in_paragraph { buf.write_string("

") } buf.to_string() } ///| /// Get doctype string for various doctype names /// Supports: html, xml, transitional, strict, frameset, 1.1, basic, mobile pub fn get_doctype(name : String) -> String { match name { "html" | "5" | "" => "" "xml" => "" "transitional" => "" "strict" => "" "frameset" => "" "1.1" => "" "basic" => "" "mobile" => "" "plist" => "" _ => "" } }