///|
/// CSS Cascade Integration with Scheduler
/// CSSカスケードとスケジューラの統合

// =============================================================================
// Style Manager
// =============================================================================

///|
/// スタイル管理 - スタイルシートとカスケード計算を管理
pub struct StyleManager {
  scheduler : Scheduler
  /// パース済みのスタイルシート
  stylesheets : Array[@css.Stylesheet]
  /// インラインスタイル (element id -> declarations)
  inline_styles : Map[String, Array[@css.Declaration]]
  /// 計算済みスタイル (element id -> cascaded values)
  computed_styles : Map[String, @css.CascadedValues]
  /// スタイルシートのソース順序カウンタ
  mut source_order : Int
}

///|
pub fn StyleManager::new(scheduler : Scheduler) -> StyleManager {
  {
    scheduler,
    stylesheets: [],
    inline_styles: {},
    computed_styles: {},
    source_order: 0,
  }
}

// =============================================================================
// Stylesheet Management
// =============================================================================

///|
/// CSSソースからスタイルシートをパースして追加
pub fn StyleManager::add_stylesheet_source(
  self : StyleManager,
  source : String,
) -> @css.Stylesheet {
  let stylesheet = @css.parse_stylesheet(
    @html.flatten_css_cascade_layers(source),
  )
  self.stylesheets.push(stylesheet)
  self.source_order += 1
  // スタイルが変更されたので再計算が必要
  self.invalidate_all_styles()
  stylesheet
}

///|
/// パース済みスタイルシートを追加
pub fn StyleManager::add_stylesheet(
  self : StyleManager,
  stylesheet : @css.Stylesheet,
) -> Unit {
  self.stylesheets.push(stylesheet)
  self.source_order += 1
  self.invalidate_all_styles()
}

///|
/// インラインスタイルを追加
pub fn StyleManager::add_inline_style(
  self : StyleManager,
  element_id : String,
  style_text : String,
) -> Unit {
  // インラインスタイルをパースして Declaration に変換
  let declarations = parse_inline_declarations(style_text)
  self.inline_styles[element_id] = declarations
  // この要素のスタイルを無効化
  self.computed_styles.remove(element_id)
}

///|
/// インラインスタイルテキストから Declaration 配列を生成
fn parse_inline_declarations(style_text : String) -> Array[@css.Declaration] {
  let declarations : Array[@css.Declaration] = []
  // "property: value; property: value" 形式をパース
  let parts = split_by_semicolon(style_text)
  for part in parts {
    let trimmed = part.trim().to_owned()
    if !trimmed.is_empty() {
      let colon_idx = find_colon(trimmed)
      if colon_idx >= 0 {
        let prop = trimmed.unsafe_substring(start=0, end=colon_idx)
        let prop_trimmed = prop.trim().to_owned()
        let val = trimmed.unsafe_substring(
          start=colon_idx + 1,
          end=trimmed.length(),
        )
        let val_trimmed = val.trim().to_owned()
        if !prop_trimmed.is_empty() && !val_trimmed.is_empty() {
          // !important チェック
          let (clean_val, importance) = if val_trimmed
            .to_lower()
            .has_suffix("!important") {
            let clean = val_trimmed.unsafe_substring(
              start=0,
              end=val_trimmed.length() - 10,
            )
            (clean.trim().to_owned(), @css.Importance::Important)
          } else {
            (val_trimmed, @css.Importance::Normal)
          }
          declarations.push(
            @css.Declaration::from_inline(prop_trimmed, clean_val, importance),
          )
        }
      }
    }
  }
  declarations
}

///|
fn split_by_semicolon(s : String) -> Array[String] {
  let result : Array[String] = []
  let current = StringBuilder::new()
  for c in s {
    if c == ';' {
      result.push(current.to_string())
      current.reset()
    } else {
      current.write_char(c)
    }
  }
  let last = current.to_string()
  if !last.is_empty() {
    result.push(last)
  }
  result
}

///|
fn find_colon(s : String) -> Int {
  let mut i = 0
  for c in s {
    if c == ':' {
      return i
    }
    i += 1
  }
  -1
}

// =============================================================================
// Style Computation
// =============================================================================

///|
/// 要素のスタイルを計算
pub fn StyleManager::compute_style(
  self : StyleManager,
  element : @css.Element,
) -> @css.CascadedValues {
  let element_id = element.id.unwrap_or("")

  // キャッシュチェック
  match self.computed_styles.get(element_id) {
    Some(cached) => return cached
    None => ()
  }

  // インラインスタイルを取得
  let inline_decls = match self.inline_styles.get(element_id) {
    Some(decls) => decls
    None => []
  }

  // カスケード計算
  let cascaded = @css.cascade_element(element, self.stylesheets, inline_decls)

  // キャッシュに保存
  if !element_id.is_empty() {
    self.computed_styles[element_id] = cascaded
  }
  cascaded
}

///|
/// 全スタイルキャッシュを無効化
pub fn StyleManager::invalidate_all_styles(self : StyleManager) -> Unit {
  self.computed_styles.clear()
}

///|
/// 特定要素のスタイルを無効化
pub fn StyleManager::invalidate_style(
  self : StyleManager,
  element_id : String,
) -> Unit {
  self.computed_styles.remove(element_id)
}

// =============================================================================
// Scheduler Integration
// =============================================================================

///|
/// CSSパースタスクを開始
pub fn StyleManager::schedule_parse_css(
  self : StyleManager,
  source : String,
) -> TaskId {
  self.scheduler.enqueue(ParseCSS(source~), MainThreadOnly)
}

///|
/// スタイル計算タスクを開始
pub fn StyleManager::schedule_compute_style(
  self : StyleManager,
  node_ids : Array[String],
) -> TaskId {
  self.scheduler.enqueue(ComputeStyle(node_ids~), MainThreadOnly)
}

///|
/// CSSパースタスク完了時の処理
pub fn StyleManager::on_css_parsed(
  self : StyleManager,
  source : String,
) -> CSSParseResult {
  let stylesheet = self.add_stylesheet_source(source)

  // スタイル再計算タスクを生成(影響を受ける可能性のある全要素)
  let recompute_task = if !self.computed_styles.is_empty() {
    let node_ids : Array[String] = []
    self.computed_styles.each(fn(id, _) { node_ids.push(id) })
    Some(self.schedule_compute_style(node_ids))
  } else {
    None
  }
  { stylesheet, recompute_task, rule_count: stylesheet.rules.length() }
}

///|
/// CSS パース結果
pub(all) struct CSSParseResult {
  stylesheet : @css.Stylesheet
  recompute_task : TaskId?
  rule_count : Int
}

// =============================================================================
// HTML + CSS Coordination
// =============================================================================

///|
/// HTMLとCSSを統合してスタイル計算をスケジュール
pub struct DocumentStyleCoordinator {
  scheduler : Scheduler
  style_manager : StyleManager
  /// パース完了したスタイルシートの数
  mut parsed_stylesheets : Int
  /// 期待されるスタイルシート数
  mut expected_stylesheets : Int
  /// スタイル計算の準備ができているか
  mut ready_for_style : Bool
}

///|
pub fn DocumentStyleCoordinator::new(
  scheduler : Scheduler,
) -> DocumentStyleCoordinator {
  {
    scheduler,
    style_manager: StyleManager::new(scheduler),
    parsed_stylesheets: 0,
    expected_stylesheets: 0,
    ready_for_style: false,
  }
}

///|
/// HTMLパース結果からスタイルシートを登録
pub fn DocumentStyleCoordinator::register_stylesheets(
  self : DocumentStyleCoordinator,
  parse_result : ParseCompleteResult,
  discovered : ResourceDiscoveryResult,
) -> Unit {
  // 外部スタイルシートの数を記録
  let external_count = discovered.filter_by_type(Stylesheet).length()

  // インラインスタイルを即座に追加
  for style_source in discovered.inline_styles {
    let _ = self.style_manager.add_stylesheet_source(style_source)
    self.parsed_stylesheets += 1
  }
  self.expected_stylesheets = external_count + discovered.inline_styles.length()

  // 外部スタイルシートがなければ即座にスタイル計算可能
  if external_count == 0 {
    self.ready_for_style = true
  }

  // HTMLから発見したインラインスタイル属性を処理
  process_element_inline_styles(parse_result.root, self.style_manager)
}

///|
/// 要素の style 属性を再帰的に処理
fn process_element_inline_styles(
  element : @html.Element,
  style_manager : StyleManager,
) -> Unit {
  // style 属性があれば追加
  match element.style {
    Some(style_text) => {
      let element_id = element.id.unwrap_or("")
      if !element_id.is_empty() {
        style_manager.add_inline_style(element_id, style_text)
      }
    }
    None => ()
  }

  // 子要素を再帰処理
  for child in element.children {
    match child {
      @html.Element(child_elem) =>
        process_element_inline_styles(child_elem, style_manager)
      @html.Text(_) => ()
    }
  }
}

///|
/// 外部スタイルシートのフェッチ完了時
pub fn DocumentStyleCoordinator::on_stylesheet_fetched(
  self : DocumentStyleCoordinator,
  css_source : String,
) -> CSSParseResult {
  let result = self.style_manager.on_css_parsed(css_source)
  self.parsed_stylesheets += 1

  // 全スタイルシートがパースされたかチェック
  if self.parsed_stylesheets >= self.expected_stylesheets {
    self.ready_for_style = true
  }
  result
}

///|
/// スタイル計算の準備ができているか
pub fn DocumentStyleCoordinator::is_ready_for_style(
  self : DocumentStyleCoordinator,
) -> Bool {
  self.ready_for_style
}

///|
/// スタイル計算をスケジュール
pub fn DocumentStyleCoordinator::schedule_style_computation(
  self : DocumentStyleCoordinator,
  node_ids : Array[String],
) -> TaskId {
  self.style_manager.schedule_compute_style(node_ids)
}

///|
/// スタイルマネージャへのアクセス
pub fn DocumentStyleCoordinator::get_style_manager(
  self : DocumentStyleCoordinator,
) -> StyleManager {
  self.style_manager
}

// =============================================================================
// Convenience Functions
// =============================================================================

///|
/// HTMLElementからselector.Elementに変換
pub fn html_element_to_selector(element : @html.Element) -> @css.Element {
  let mut sel_elem = @css.Element::new(element.tag)

  // IDを設定
  match element.id {
    Some(id) => sel_elem = sel_elem.set_id(id)
    None => ()
  }

  // クラスを追加
  for class in element.classes {
    sel_elem = sel_elem.add_class(class)
  }

  // 属性を追加
  element.attributes.each(fn(name, value) {
    sel_elem = sel_elem.set_attribute(name, value)
  })
  sel_elem
}

///|
/// HTMLElementのスタイルを計算
pub fn compute_element_style(
  style_manager : StyleManager,
  element : @html.Element,
) -> @css.CascadedValues {
  let selector_elem = html_element_to_selector(element)
  style_manager.compute_style(selector_elem)
}