///|
/// CDP Page Domain
///
/// Implements Chrome DevTools Protocol Page domain.
/// Handles page navigation, lifecycle, and content.

///|
/// Page Domain handler
pub struct PageDomain {
  tree : @dom.DomTree
  /// Current URL
  mut current_url : String
  /// Page title
  mut title : String
  /// Frame ID
  frame_id : String
  /// Loader ID (changes on each navigation)
  mut loader_id : Int
  /// Navigation history
  history : Array[CdpNavigationEntry]
  /// Current history index
  mut history_index : Int
}

///|
/// Create new Page domain
pub fn PageDomain::new(tree : @dom.DomTree) -> PageDomain {
  {
    tree,
    current_url: "about:blank",
    title: "",
    frame_id: "main-frame",
    loader_id: 1,
    history: [],
    history_index: -1,
  }
}

// =============================================================================
// Navigation
// =============================================================================

///|
/// Page.navigate - Navigates to URL
/// Note: Actual fetching is done externally, this just updates state
pub fn PageDomain::navigate(
  self : PageDomain,
  url : String,
) -> Result[CdpNavigateResult, CdpError] {
  // Update loader ID
  self.loader_id += 1
  let loader_id = "loader-" + self.loader_id.to_string()
  // Update current URL
  self.current_url = url
  // Add to history
  self.history_index += 1
  // Truncate forward history if any
  while self.history.length() > self.history_index {
    let _ = self.history.pop()
  }
  self.history.push({
    id: self.history_index,
    url,
    title: self.title,
    transition_type: "typed",
  })
  Ok({ frame_id: self.frame_id, loader_id, error_text: None })
}

///|
/// Update URL/history for History API pushState without full navigation.
pub fn PageDomain::push_history_url(self : PageDomain, url : String) -> Unit {
  self.current_url = url
  self.history_index += 1
  while self.history.length() > self.history_index {
    let _ = self.history.pop()
  }
  self.history.push({
    id: self.history_index,
    url,
    title: self.title,
    transition_type: "pushState",
  })
}

///|
/// Update URL/history for History API replaceState without adding an entry.
pub fn PageDomain::replace_history_url(self : PageDomain, url : String) -> Unit {
  self.current_url = url
  if self.history_index >= 0 && self.history_index < self.history.length() {
    self.history[self.history_index] = {
      ..self.history[self.history_index],
      url,
    }
    return
  }
  self.history.push({
    id: 0,
    url,
    title: self.title,
    transition_type: "replaceState",
  })
  self.history_index = self.history.length() - 1
}

///|
/// Page.reload - Reloads the current page
pub fn PageDomain::reload(self : PageDomain) -> Result[Unit, CdpError] {
  // Increment loader ID
  self.loader_id += 1
  Ok(())
}

///|
/// Page.goBack - Goes back in history
pub fn PageDomain::go_back(self : PageDomain) -> Result[Bool, CdpError] {
  if self.history_index > 0 {
    self.history_index -= 1
    let entry = self.history[self.history_index]
    self.current_url = entry.url
    self.title = entry.title
    self.loader_id += 1
    Ok(true)
  } else {
    Ok(false)
  }
}

///|
/// Page.goForward - Goes forward in history
pub fn PageDomain::go_forward(self : PageDomain) -> Result[Bool, CdpError] {
  if self.history_index < self.history.length() - 1 {
    self.history_index += 1
    let entry = self.history[self.history_index]
    self.current_url = entry.url
    self.title = entry.title
    self.loader_id += 1
    Ok(true)
  } else {
    Ok(false)
  }
}

///|
/// Page.getNavigationHistory - Returns navigation history
pub fn PageDomain::get_navigation_history(
  self : PageDomain,
) -> Result[CdpNavigationHistory, CdpError] {
  Ok({ current_index: self.history_index, entries: self.history })
}

// =============================================================================
// Frame Info
// =============================================================================

///|
/// Page.getFrameTree - Returns frame tree
pub fn PageDomain::get_frame_tree(
  self : PageDomain,
) -> Result[CdpFrameInfo, CdpError] {
  Ok({
    id: self.frame_id,
    parent_id: None,
    loader_id: "loader-" + self.loader_id.to_string(),
    name: "",
    url: self.current_url,
    security_origin: extract_origin(self.current_url),
    mime_type: "text/html",
  })
}

// =============================================================================
// Content
// =============================================================================

///|
/// Set page title (called when document is loaded)
pub fn PageDomain::set_title(self : PageDomain, title : String) -> Unit {
  self.title = title
  // Update history entry
  if self.history_index >= 0 && self.history_index < self.history.length() {
    self.history[self.history_index] = {
      ..self.history[self.history_index],
      title,
    }
  }
}

///|
/// Get current URL
pub fn PageDomain::get_url(self : PageDomain) -> String {
  self.current_url
}

///|
/// Get page title
pub fn PageDomain::get_title(self : PageDomain) -> String {
  self.title
}

// =============================================================================
// Types
// =============================================================================

///|
/// Navigate result
pub struct CdpNavigateResult {
  frame_id : String
  loader_id : String
  error_text : String?
} derive(Debug)

///|
/// Navigation history
pub struct CdpNavigationHistory {
  current_index : Int
  entries : Array[CdpNavigationEntry]
} derive(Debug)

// =============================================================================
// Helpers
// =============================================================================

///|
/// Extract origin from URL
fn extract_origin(url : String) -> String {
  // Simple origin extraction
  match url.find("://") {
    Some(i) => {
      let after_protocol = url.unsafe_substring(start=i + 3, end=url.length())
      match after_protocol.find("/") {
        Some(j) => url.unsafe_substring(start=0, end=i + 3 + j)
        None => url
      }
    }
    None => url
  }
}