///|
/// WebDriver Handler - Connects WebDriver/RPC protocol to CDP implementation
///
/// This module provides the dispatch layer that routes incoming
/// API commands to CDP-based browser operations.

// =============================================================================
// RPC Handler
// =============================================================================

///|
/// Handle an RPC request and return a response
/// This is the main entry point for processing JSON-RPC requests
pub fn handle_rpc(
  manager : CdpSessionManager,
  request : RpcRequest,
) -> RpcResponse {
  let id = request.id
  let parsed = parse_method(request.method_name)
  match parsed {
    None =>
      rpc_error(id, MethodNotFound, "Unknown method: " + request.method_name)
    Some(api_method) => dispatch_method(manager, id, api_method, request.params)
  }
}

///|
/// Dispatch an API method to the appropriate handler
fn dispatch_method(
  manager : CdpSessionManager,
  id : RpcId,
  api_method : ApiMethod,
  params : Map[String, String],
) -> RpcResponse {
  match api_method {
    // Context management (session = page in this simplified model)
    NewContext => {
      let session_id = manager.create_session()
      rpc_success_string(id, session_id)
    }
    CloseContext(context_id~) => {
      let ctx_id = params.get("context_id").unwrap_or(context_id)
      if manager.close_session(ctx_id) {
        rpc_success_null(id)
      } else {
        api_error_to_rpc(id, ContextNotFound(context_id=ctx_id))
      }
    }
    // Navigation
    Goto(page_id~, url~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      let nav_url = params.get("url").unwrap_or(url)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) =>
          match handle_navigate(session, nav_url) {
            Ok(_) => rpc_success_null(id)
            Err(err) => {
              let (_, message) = err.to_w3c_error()
              api_error_to_rpc(
                id,
                NavigationFailed(url=nav_url, reason=message),
              )
            }
          }
      }
    }
    GoBack(page_id~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) => {
          let page = session.get_page()
          match page.go_back() {
            Ok(true) => rpc_success_string(id, page.get_url())
            Ok(false) => rpc_success_null(id)
            Err(e) => api_error_to_rpc(id, InternalError(message=e.message))
          }
        }
      }
    }
    GoForward(page_id~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) => {
          let page = session.get_page()
          match page.go_forward() {
            Ok(true) => rpc_success_string(id, page.get_url())
            Ok(false) => rpc_success_null(id)
            Err(e) => api_error_to_rpc(id, InternalError(message=e.message))
          }
        }
      }
    }
    Reload(page_id~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) => {
          let page = session.get_page()
          match page.reload() {
            Ok(_) => rpc_success_null(id)
            Err(e) => api_error_to_rpc(id, InternalError(message=e.message))
          }
        }
      }
    }
    // Page state
    Url(page_id~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) => rpc_success_string(id, handle_get_current_url(session))
      }
    }
    Title(page_id~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) => rpc_success_string(id, handle_get_title(session))
      }
    }
    Content(page_id~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) => {
          // Get outer HTML of document
          let dom = session.get_dom()
          let doc_id = session.get_tree().get_document().to_int()
          match dom.get_outer_html(doc_id) {
            Ok(html) => rpc_success_string(id, html)
            Err(e) => api_error_to_rpc(id, InternalError(message=e.message))
          }
        }
      }
    }
    // Element finding
    Query(page_id~, selector~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      let sel = params.get("selector").unwrap_or(selector)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) =>
          match handle_find_element(session, "css selector", sel) {
            Ok(element_id) =>
              rpc_success_string(id, "element-" + element_id.to_string())
            Err(err) => {
              let (_, message) = err.to_w3c_error()
              api_error_to_rpc(id, ElementNotFound(selector=message))
            }
          }
      }
    }
    QueryAll(page_id~, selector~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      let sel = params.get("selector").unwrap_or(selector)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) =>
          match handle_find_elements(session, "css selector", sel) {
            Ok(element_ids) => {
              let ids_json = element_ids
                .map(fn(eid) { "\"element-" + eid.to_string() + "\"" })
                .join(",")
              rpc_success_json(id, "[" + ids_json + "]")
            }
            Err(err) => {
              let (_, message) = err.to_w3c_error()
              api_error_to_rpc(id, ElementNotFound(selector=message))
            }
          }
      }
    }
    // Element operations
    TextContent(element_id~) => {
      let elem_id = params.get("element_id").unwrap_or(element_id)
      handle_element_op(manager, id, elem_id, fn(session, node_id) {
        handle_get_element_text(session, node_id)
      })
    }
    GetAttribute(element_id~, name~) => {
      let elem_id = params.get("element_id").unwrap_or(element_id)
      let attr_name = params.get("name").unwrap_or(name)
      handle_element_attr_op(manager, id, elem_id, attr_name)
    }
    Click(element_id~) => {
      let elem_id = params.get("element_id").unwrap_or(element_id)
      handle_element_click_op(manager, id, elem_id)
    }
    // Screenshot (returns DOM tree as text)
    Screenshot(page_id~) => {
      let ctx_id = params.get("page_id").unwrap_or(page_id)
      match manager.get_session(ctx_id) {
        None => api_error_to_rpc(id, PageNotFound(page_id=ctx_id))
        Some(session) => {
          let dom = session.get_dom()
          let doc_id = session.get_tree().get_document().to_int()
          match dom.get_outer_html(doc_id) {
            Ok(html) => rpc_success_string(id, html)
            Err(e) => api_error_to_rpc(id, InternalError(message=e.message))
          }
        }
      }
    }
    // Not implemented yet
    _ => rpc_error(id, MethodNotFound, "Method not yet implemented")
  }
}

// =============================================================================
// Helper Functions
// =============================================================================

///|
/// Parse element ID string to node ID
fn parse_element_id(element_id : String) -> Int? {
  // Format: "element-123" or just "123"
  let id_str = if element_id.has_prefix("element-") {
    element_id.unsafe_substring(start=8, end=element_id.length())
  } else {
    element_id
  }
  Some(@string.parse_int(id_str)) catch {
    _ => None
  }
}

///|
/// Get session from element ID (format: "ctx-1:element-123" or "element-123")
fn get_session_for_element(
  manager : CdpSessionManager,
  element_id : String,
) -> (@cdp.CdpSession, Int)? {
  // Try to find session containing this element
  // For now, search all sessions
  let node_id = match parse_element_id(element_id) {
    Some(id) => id
    None => return None
  }
  for session_id in manager.list_sessions() {
    match manager.get_session(session_id) {
      Some(session) => return Some((session, node_id))
      None => continue
    }
  }
  None
}

///|
/// Handle element operation with common error handling
fn handle_element_op(
  manager : CdpSessionManager,
  id : RpcId,
  element_id : String,
  op : (@cdp.CdpSession, Int) -> Result[String, CdpHandlerError],
) -> RpcResponse {
  match get_session_for_element(manager, element_id) {
    None => api_error_to_rpc(id, ElementNotFound(selector=element_id))
    Some((session, node_id)) =>
      match op(session, node_id) {
        Ok(result) => rpc_success_string(id, result)
        Err(err) => {
          let (_, message) = err.to_w3c_error()
          api_error_to_rpc(id, InternalError(message~))
        }
      }
  }
}

///|
/// Handle element attribute operation
fn handle_element_attr_op(
  manager : CdpSessionManager,
  id : RpcId,
  element_id : String,
  attr_name : String,
) -> RpcResponse {
  match get_session_for_element(manager, element_id) {
    None => api_error_to_rpc(id, ElementNotFound(selector=element_id))
    Some((session, node_id)) =>
      match handle_get_element_attribute(session, node_id, attr_name) {
        Ok(Some(value)) => rpc_success_string(id, value)
        Ok(None) => rpc_success_null(id)
        Err(err) => {
          let (_, message) = err.to_w3c_error()
          api_error_to_rpc(id, InternalError(message~))
        }
      }
  }
}

///|
/// Handle element click operation
fn handle_element_click_op(
  manager : CdpSessionManager,
  id : RpcId,
  element_id : String,
) -> RpcResponse {
  match get_session_for_element(manager, element_id) {
    None => api_error_to_rpc(id, ElementNotFound(selector=element_id))
    Some((session, node_id)) =>
      match handle_element_click(session, node_id) {
        Ok(_) => rpc_success_null(id)
        Err(err) => {
          let (_, message) = err.to_w3c_error()
          api_error_to_rpc(id, InternalError(message~))
        }
      }
  }
}