package daemon

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/go-rod/rod"
	"github.com/go-rod/rod/lib/launcher"
	"github.com/go-rod/rod/lib/proto"
)

const Version = "2.0.0"

// Daemon is the main server that manages browser connections
type Daemon struct {
	browser     *rod.Browser
	tabs        map[string]*rod.Page
	iframePages map[string]*rod.Page    // Maps tab ID to iframe page context
	currentTab  string                  // ID of the current/last used tab
	tabHistory  []string                // Stack of tab IDs in order of activation (LIFO)
	consoleLogs map[string][]ConsoleLog // Maps tab ID to console logs
	debug       bool                    // Enable debug logging
	mu          sync.Mutex
	server      *http.Server
}

// ConsoleLog represents a console log entry
type ConsoleLog struct {
	Level     string    `json:"level"`     // log, warn, error, info, debug
	Message   string    `json:"message"`   // The log message
	Timestamp time.Time `json:"timestamp"` // When the log occurred
	Source    string    `json:"source"`    // Source location if available
}

// Command represents a command sent from the client to the daemon
type Command struct {
	Action string            `json:"action"`
	Params map[string]string `json:"params"`
}

// Response represents a response from the daemon to the client
type Response struct {
	Success bool        `json:"success"`
	Data    interface{} `json:"data,omitempty"`
	Error   string      `json:"error,omitempty"`
}

// checkChromeRunning checks if Chrome is running on the debug port
func checkChromeRunning(port int) bool {
	conn, err := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), 2*time.Second)
	if err != nil {
		return false
	}
	conn.Close()
	return true
}

// checkChromeDevTools checks if Chrome DevTools protocol is responding
func checkChromeDevTools(port int) bool {
	resp, err := http.Get(fmt.Sprintf("http://localhost:%d/json/version", port))
	if err != nil {
		return false
	}
	defer resp.Body.Close()
	return resp.StatusCode == 200
}

// debugLog logs a message only if debug mode is enabled
func (d *Daemon) debugLog(format string, args ...interface{}) {
	if d.debug {
		log.Printf("[DEBUG] "+format, args...)
	}
}

// NewDaemon creates a new daemon instance
func NewDaemon(host string, port int, debug bool) (*Daemon, error) {
	if debug {
		log.Printf("[DEBUG] Creating new daemon on %s:%d", host, port)
	}

	// Check if Chrome is running on the debug port
	chromePort := 9222 // Default Chrome debug port

	if debug {
		log.Printf("[DEBUG] Checking if Chrome is running on port %d", chromePort)
	}

	if !checkChromeRunning(chromePort) {
		return nil, fmt.Errorf("Chromium is not running with remote debugging enabled on port %d.\n\nTo start Chromium with remote debugging:\n  chromium --remote-debugging-port=%d --user-data-dir=/tmp/chromium-debug &\n  # or\n  google-chrome --remote-debugging-port=%d --user-data-dir=/tmp/chrome-debug &\n\nNote: The --user-data-dir flag is required to avoid conflicts with existing browser instances.", chromePort, chromePort, chromePort)
	}

	// Check if Chromium DevTools protocol is responding
	if !checkChromeDevTools(chromePort) {
		return nil, fmt.Errorf("Something is listening on port %d but it's not Chromium DevTools protocol.\n\nThis might be:\n1. Chromium running without --remote-debugging-port=%d\n2. Another application using port %d\n\nTry stopping the process on port %d and starting Chromium with:\n  chromium --remote-debugging-port=%d --user-data-dir=/tmp/chromium-debug &", chromePort, chromePort, chromePort, chromePort, chromePort)
	}

	// Connect to the existing browser instance
	u := launcher.MustResolveURL("")
	browser := rod.New().ControlURL(u)

	err := browser.Connect()
	if err != nil {
		return nil, fmt.Errorf("Chromium DevTools is responding on port %d but rod connection failed: %w\n\nThis is unexpected. Try restarting Chromium with:\n  chromium --remote-debugging-port=%d --user-data-dir=/tmp/chromium-debug &", chromePort, err, chromePort)
	}

	if debug {
		log.Printf("[DEBUG] Successfully connected to browser via rod")
	}

	daemon := &Daemon{
		browser:     browser,
		tabs:        make(map[string]*rod.Page),
		iframePages: make(map[string]*rod.Page),
		tabHistory:  make([]string, 0),
		consoleLogs: make(map[string][]ConsoleLog),
		debug:       debug,
	}

	daemon.debugLog("Daemon struct initialized")

	// Create HTTP server
	daemon.debugLog("Setting up HTTP server")
	mux := http.NewServeMux()
	mux.HandleFunc("/command", daemon.handleCommand)
	mux.HandleFunc("/status", daemon.handleStatus)
	mux.HandleFunc("/upload", daemon.handleFileUpload)
	mux.HandleFunc("/download", daemon.handleFileDownload)

	daemon.server = &http.Server{
		Addr:    fmt.Sprintf("%s:%d", host, port),
		Handler: mux,
	}

	daemon.debugLog("HTTP server configured on %s:%d", host, port)

	return daemon, nil
}

// Start starts the daemon server
func (d *Daemon) Start() error {
	log.Printf("Starting daemon server on %s", d.server.Addr)
	d.debugLog("About to call ListenAndServe()")
	err := d.server.ListenAndServe()
	d.debugLog("ListenAndServe() returned with error: %v", err)
	return err
}

// Stop stops the daemon server
func (d *Daemon) Stop() error {
	log.Println("Stopping daemon server")
	return d.server.Close()
}

// handleStatus handles status requests
func (d *Daemon) handleStatus(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	d.mu.Lock()
	tabCount := len(d.tabs)
	tabs := make(map[string]string)
	currentTab := d.currentTab
	tabHistory := make([]string, len(d.tabHistory))
	copy(tabHistory, d.tabHistory)

	// Get info about each tab
	for id, page := range d.tabs {
		try := func() string {
			info, err := page.Info()
			if err != nil {
				return "<unavailable>"
			}
			return info.URL
		}
		tabs[id] = try()
	}
	d.mu.Unlock()

	response := Response{
		Success: true,
		Data: map[string]interface{}{
			"status":      "running",
			"tab_count":   tabCount,
			"tabs":        tabs,
			"current_tab": currentTab,
			"tab_history": tabHistory,
		},
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// handleCommand handles command requests
func (d *Daemon) handleCommand(w http.ResponseWriter, r *http.Request) {
	d.debugLog("Received HTTP request: %s %s", r.Method, r.URL.Path)

	if r.Method != http.MethodPost {
		d.debugLog("Invalid method: %s", r.Method)
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var cmd Command
	err := json.NewDecoder(r.Body).Decode(&cmd)
	if err != nil {
		d.debugLog("Failed to decode JSON: %v", err)
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	d.debugLog("Processing command: %s with params: %+v", cmd.Action, cmd.Params)

	var response Response

	switch cmd.Action {
	case "version":
		response = Response{
			Success: true,
			Data:    Version,
		}

	case "open-tab":
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		tabID, err := d.openTab(timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: tabID}
		}

	case "load-url":
		tabID := cmd.Params["tab"]
		url := cmd.Params["url"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		err := d.loadURL(tabID, url, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "fill-form":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		value := cmd.Params["value"]

		// Parse timeouts
		selectionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["selection-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				selectionTimeout = parsedTimeout
			}
		}

		actionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["action-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				actionTimeout = parsedTimeout
			}
		}

		err := d.fillFormField(tabID, selector, value, selectionTimeout, actionTimeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "upload-file":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		filePath := cmd.Params["file"]

		// Parse timeouts
		selectionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["selection-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				selectionTimeout = parsedTimeout
			}
		}

		actionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["action-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				actionTimeout = parsedTimeout
			}
		}

		err := d.uploadFile(tabID, selector, filePath, selectionTimeout, actionTimeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "submit-form":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]

		// Parse timeouts
		selectionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["selection-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				selectionTimeout = parsedTimeout
			}
		}

		actionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["action-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				actionTimeout = parsedTimeout
			}
		}

		err := d.submitForm(tabID, selector, selectionTimeout, actionTimeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "get-source":
		tabID := cmd.Params["tab"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		source, err := d.getPageSource(tabID, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: source}
		}

	case "get-element":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]

		// Parse timeouts
		selectionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["selection-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				selectionTimeout = parsedTimeout
			}
		}

		html, err := d.getElementHTML(tabID, selector, selectionTimeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: html}
		}

	case "close-tab":
		tabID := cmd.Params["tab"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		err := d.closeTab(tabID, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "wait-navigation":
		tabID := cmd.Params["tab"]
		timeout := 5 // Default timeout
		if timeoutStr, ok := cmd.Params["timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}
		err := d.waitNavigation(tabID, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "click-element":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]

		// Parse timeouts
		selectionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["selection-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				selectionTimeout = parsedTimeout
			}
		}

		actionTimeout := 5 // Default: 5 seconds
		if timeoutStr, ok := cmd.Params["action-timeout"]; ok {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				actionTimeout = parsedTimeout
			}
		}

		err := d.clickElement(tabID, selector, selectionTimeout, actionTimeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "eval-js":
		tabID := cmd.Params["tab"]
		jsCode := cmd.Params["code"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.evalJS(tabID, jsCode, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "switch-iframe":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		err := d.switchToIframe(tabID, selector, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "switch-main":
		tabID := cmd.Params["tab"]

		err := d.switchToMain(tabID)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "screenshot":
		tabID := cmd.Params["tab"]
		outputPath := cmd.Params["output"]
		fullPageStr := cmd.Params["full-page"]
		timeoutStr := cmd.Params["timeout"]

		// Parse full-page flag
		fullPage := false
		if fullPageStr == "true" {
			fullPage = true
		}

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		err := d.takeScreenshot(tabID, outputPath, fullPage, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "console-logs":
		tabID := cmd.Params["tab"]
		clearStr := cmd.Params["clear"]

		// Parse clear flag
		clear := false
		if clearStr == "true" {
			clear = true
		}

		logs, err := d.getConsoleLogs(tabID, clear)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: logs}
		}

	case "console-command":
		tabID := cmd.Params["tab"]
		command := cmd.Params["command"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.executeConsoleCommand(tabID, command, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "check-element":
		d.debugLog("Processing check-element command")
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		checkType := cmd.Params["type"] // exists, visible, enabled, focused, selected
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.checkElement(tabID, selector, checkType, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "get-element-attributes":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		attributes := cmd.Params["attributes"] // comma-separated list or "all"
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.getElementAttributes(tabID, selector, attributes, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "count-elements":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		count, err := d.countElements(tabID, selector, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: count}
		}

	case "extract-multiple":
		tabID := cmd.Params["tab"]
		selectors := cmd.Params["selectors"] // JSON array of selectors
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.extractMultiple(tabID, selectors, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "extract-links":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]        // Optional: filter links by container selector
		hrefPattern := cmd.Params["href-pattern"] // Optional: regex pattern for href
		textPattern := cmd.Params["text-pattern"] // Optional: regex pattern for link text
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.extractLinks(tabID, selector, hrefPattern, textPattern, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "extract-table":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		includeHeaders := cmd.Params["include-headers"] == "true"
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.extractTable(tabID, selector, includeHeaders, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "extract-text":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		pattern := cmd.Params["pattern"]  // Optional: regex pattern to match within text
		extractType := cmd.Params["type"] // text, innerText, textContent (default: textContent)
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.extractText(tabID, selector, pattern, extractType, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "analyze-form":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.analyzeForm(tabID, selector, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "interact-multiple":
		tabID := cmd.Params["tab"]
		interactionsJSON := cmd.Params["interactions"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.interactMultiple(tabID, interactionsJSON, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "fill-form-bulk":
		tabID := cmd.Params["tab"]
		formSelector := cmd.Params["form-selector"]
		fieldsJSON := cmd.Params["fields"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.fillFormBulk(tabID, formSelector, fieldsJSON, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "get-page-info":
		tabID := cmd.Params["tab"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.getPageInfo(tabID, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "get-viewport-info":
		tabID := cmd.Params["tab"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.getViewportInfo(tabID, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "get-performance":
		tabID := cmd.Params["tab"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.getPerformance(tabID, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "check-content":
		tabID := cmd.Params["tab"]
		contentType := cmd.Params["type"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.checkContent(tabID, contentType, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "screenshot-element":
		tabID := cmd.Params["tab"]
		selector := cmd.Params["selector"]
		outputPath := cmd.Params["output"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		err := d.screenshotElement(tabID, selector, outputPath, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true}
		}

	case "screenshot-enhanced":
		tabID := cmd.Params["tab"]
		outputPath := cmd.Params["output"]
		fullPageStr := cmd.Params["full-page"]
		timeoutStr := cmd.Params["timeout"]

		// Parse full-page flag
		fullPage := false
		if fullPageStr == "true" {
			fullPage = true
		}

		// Parse timeout (default to 5 seconds if not specified)
		timeout := 5
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.screenshotEnhanced(tabID, outputPath, fullPage, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "bulk-files":
		operationType := cmd.Params["operation"] // "upload" or "download"
		filesJSON := cmd.Params["files"]
		timeoutStr := cmd.Params["timeout"]

		// Parse timeout (default to 30 seconds for bulk operations)
		timeout := 30
		if timeoutStr != "" {
			if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
				timeout = parsedTimeout
			}
		}

		result, err := d.bulkFiles(operationType, filesJSON, timeout)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	case "manage-files":
		operation := cmd.Params["operation"] // "cleanup", "list", "info"
		pattern := cmd.Params["pattern"]     // file pattern for cleanup/list
		maxAge := cmd.Params["max-age"]      // max age in hours for cleanup

		result, err := d.manageFiles(operation, pattern, maxAge)
		if err != nil {
			response = Response{Success: false, Error: err.Error()}
		} else {
			response = Response{Success: true, Data: result}
		}

	default:
		d.debugLog("Unknown action: %s", cmd.Action)
		response = Response{Success: false, Error: "Unknown action"}
	}

	d.debugLog("Command %s completed, sending response: success=%v", cmd.Action, response.Success)
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
	d.debugLog("Response sent for command: %s", cmd.Action)
}

// openTab opens a new tab and returns its ID
func (d *Daemon) openTab(timeout int) (string, error) {
	d.debugLog("Opening new tab with timeout: %d", timeout)
	d.mu.Lock()
	defer d.mu.Unlock()

	// Create a context with timeout if specified
	if timeout > 0 {
		d.debugLog("Using timeout context: %d seconds", timeout)
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan struct {
			page  *rod.Page
			tabID string
			err   error
		}, 1)

		// Execute the tab creation in a goroutine
		go func() {
			page, err := d.browser.Page(proto.TargetCreateTarget{URL: "about:blank"})
			var tabID string
			if err == nil {
				tabID = string(page.TargetID)
			}
			done <- struct {
				page  *rod.Page
				tabID string
				err   error
			}{page, tabID, err}
		}()

		// Wait for either completion or timeout
		select {
		case res := <-done:
			if res.err != nil {
				return "", fmt.Errorf("failed to create new tab: %w", res.err)
			}

			// Store the tab and update history
			d.tabs[res.tabID] = res.page
			d.tabHistory = append(d.tabHistory, res.tabID)
			d.currentTab = res.tabID

			// Set up console logging for this tab
			d.setupConsoleLogging(res.tabID, res.page)

			return res.tabID, nil
		case <-ctx.Done():
			return "", fmt.Errorf("opening tab timed out after %d seconds", timeout)
		}
	} else {
		// No timeout
		page, err := d.browser.Page(proto.TargetCreateTarget{URL: "about:blank"})
		if err != nil {
			return "", fmt.Errorf("failed to create new tab: %w", err)
		}

		// Use the page ID as the tab ID
		tabID := string(page.TargetID)
		d.tabs[tabID] = page

		// Add to tab history stack and set as current tab
		d.tabHistory = append(d.tabHistory, tabID)
		d.currentTab = tabID

		// Set up console logging for this tab
		d.setupConsoleLogging(tabID, page)

		return tabID, nil
	}
}

// getTabID returns the tab ID to use, falling back to the current tab if none is provided
func (d *Daemon) getTabID(tabID string) (string, error) {
	d.mu.Lock()
	defer d.mu.Unlock()

	// If no tab ID is provided, use the current tab
	if tabID == "" {
		if d.currentTab == "" {
			return "", fmt.Errorf("no current tab available, please open a tab first")
		}
		return d.currentTab, nil
	}

	// Otherwise, use the provided tab ID
	return tabID, nil
}

// updateTabHistory updates the tab history stack when a tab is activated
func (d *Daemon) updateTabHistory(tabID string) {
	// Set as current tab
	d.currentTab = tabID

	// Remove the tab from history if it's already there
	for i, id := range d.tabHistory {
		if id == tabID {
			// Remove this tab from history
			d.tabHistory = append(d.tabHistory[:i], d.tabHistory[i+1:]...)
			break
		}
	}

	// Add the tab to the end of history (most recent)
	d.tabHistory = append(d.tabHistory, tabID)
}

// findPageByID finds a page by its ID without updating the current tab or cache
func (d *Daemon) findPageByID(tabID string) (*rod.Page, error) {
	// If not in memory, try to get the page from the browser
	pages, err := d.browser.Pages()
	if err != nil {
		return nil, fmt.Errorf("failed to get browser pages: %w", err)
	}

	// Find the page with the matching ID
	for _, p := range pages {
		if string(p.TargetID) == tabID {
			return p, nil
		}
	}

	return nil, fmt.Errorf("tab not found: %s", tabID)
}

// getTab returns a tab by its ID, checking for iframe context first
func (d *Daemon) getTab(tabID string) (*rod.Page, error) {
	// Get the tab ID to use (may be the current tab)
	actualTabID, err := d.getTabID(tabID)
	if err != nil {
		return nil, err
	}

	d.mu.Lock()
	defer d.mu.Unlock()

	// First check if we have an iframe context for this tab
	if iframePage, exists := d.iframePages[actualTabID]; exists {
		// Update tab history and current tab
		d.updateTabHistory(actualTabID)
		return iframePage, nil
	}

	// Check in-memory cache for main page
	page, exists := d.tabs[actualTabID]
	if exists {
		// Update tab history and current tab
		d.updateTabHistory(actualTabID)
		return page, nil
	}

	// If not in memory, try to find it
	page, err = d.findPageByID(actualTabID)
	if err != nil {
		return nil, err
	}

	// If found, cache it for future use
	if page != nil {
		d.tabs[actualTabID] = page
		// Update tab history and current tab
		d.updateTabHistory(actualTabID)
		return page, nil
	}

	return nil, fmt.Errorf("tab not found: %s", actualTabID)
}

// closeTab closes a tab by its ID
func (d *Daemon) closeTab(tabID string, timeout int) error {
	// Get the tab ID to use (may be the current tab)
	actualTabID, err := d.getTabID(tabID)
	if err != nil {
		return err
	}

	// First remove from our internal map to avoid future references
	d.mu.Lock()
	page, exists := d.tabs[actualTabID]
	delete(d.tabs, actualTabID)

	// Remove the tab from history
	for i, id := range d.tabHistory {
		if id == actualTabID {
			// Remove this tab from history
			d.tabHistory = append(d.tabHistory[:i], d.tabHistory[i+1:]...)
			break
		}
	}

	// If we closed the current tab, set it to the previous tab in history
	if d.currentTab == actualTabID {
		if len(d.tabHistory) > 0 {
			// Set current tab to the most recent tab in history
			d.currentTab = d.tabHistory[len(d.tabHistory)-1]
		} else {
			// No tabs left in history, clear the current tab
			d.currentTab = ""
		}
	}
	d.mu.Unlock()

	// If the page doesn't exist in our cache, try to find it
	if !exists {
		var err error
		page, err = d.findPageByID(actualTabID)
		if err != nil {
			// If we can't find the page, it might already be closed
			return nil
		}
	}

	if timeout > 0 {
		// Use timeout for closing the tab
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan error, 1)

		// Execute the close in a goroutine
		go func() {
			err := page.Close()
			done <- err
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			if err != nil {
				// Log the error but don't return it, as we've already removed it from our map
				fmt.Printf("Warning: failed to close tab %s: %v\n", actualTabID, err)
			}
			return nil
		case <-ctx.Done():
			return fmt.Errorf("closing tab timed out after %d seconds", timeout)
		}
	} else {
		// No timeout - try to close the page, but don't fail if it's already closed
		err = page.Close()
		if err != nil {
			// Log the error but don't return it, as we've already removed it from our map
			fmt.Printf("Warning: failed to close tab %s: %v\n", actualTabID, err)
		}

		return nil
	}
}

// loadURL loads a URL in a tab
func (d *Daemon) loadURL(tabID, url string, timeout int) error {
	d.debugLog("Loading URL: %s in tab: %s with timeout: %d", url, tabID, timeout)
	page, err := d.getTab(tabID)
	if err != nil {
		d.debugLog("Failed to get tab %s: %v", tabID, err)
		return err
	}
	d.debugLog("Got tab %s, starting navigation", tabID)

	if timeout > 0 {
		// Use timeout for the URL loading
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan error, 1)

		// Execute the navigation in a goroutine
		go func() {
			err := page.Navigate(url)
			if err != nil {
				done <- fmt.Errorf("failed to navigate to URL: %w", err)
				return
			}

			// Wait for the page to be loaded
			err = page.WaitLoad()
			if err != nil {
				done <- fmt.Errorf("failed to wait for page load: %w", err)
				return
			}

			done <- nil
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			return err
		case <-ctx.Done():
			return fmt.Errorf("loading URL timed out after %d seconds", timeout)
		}
	} else {
		// No timeout
		err = page.Navigate(url)
		if err != nil {
			return fmt.Errorf("failed to navigate to URL: %w", err)
		}

		// Wait for the page to be loaded
		err = page.WaitLoad()
		if err != nil {
			return fmt.Errorf("failed to wait for page load: %w", err)
		}

		return nil
	}
}

// isPageStable checks if a page is stable and not currently loading
func (d *Daemon) isPageStable(page *rod.Page) (bool, error) {
	// Check if page is loading
	result, err := page.Eval(`() => document.readyState === 'complete'`)
	if err != nil {
		return false, err
	}

	isComplete := result.Value.Bool()

	if !isComplete {
		return false, nil
	}

	// Additional check: ensure no pending network requests
	// This is a simple heuristic - if the page has been stable for a short time
	err = page.WaitStable(500 * time.Millisecond)
	if err != nil {
		return false, nil // Page is not stable
	}

	return true, nil
}

// detectNavigationInProgress monitors the page for a short period to detect if navigation starts
func (d *Daemon) detectNavigationInProgress(page *rod.Page, monitorDuration time.Duration) (bool, error) {
	// Get current URL and readyState
	currentURL, err := page.Eval(`() => window.location.href`)
	if err != nil {
		return false, err
	}

	currentReadyState, err := page.Eval(`() => document.readyState`)
	if err != nil {
		return false, err
	}

	startURL := currentURL.Value.Str()
	startReadyState := currentReadyState.Value.Str()

	// Monitor for changes over the specified duration
	ctx, cancel := context.WithTimeout(context.Background(), monitorDuration)
	defer cancel()

	ticker := time.NewTicker(100 * time.Millisecond)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			// No navigation detected during monitoring period
			return false, nil
		case <-ticker.C:
			// Check if URL or readyState changed
			newURL, err := page.Eval(`() => window.location.href`)
			if err != nil {
				continue // Ignore errors during monitoring
			}

			newReadyState, err := page.Eval(`() => document.readyState`)
			if err != nil {
				continue // Ignore errors during monitoring
			}

			if newURL.Value.Str() != startURL {
				// URL changed, navigation is happening
				return true, nil
			}

			if newReadyState.Value.Str() != startReadyState && newReadyState.Value.Str() == "loading" {
				// Page started loading
				return true, nil
			}
		}
	}
}

// waitNavigation waits for a navigation event to happen
func (d *Daemon) waitNavigation(tabID string, timeout int) error {
	page, err := d.getTab(tabID)
	if err != nil {
		return err
	}

	// First, check if the page is already stable and loaded
	// If so, we don't need to wait for navigation
	isStable, err := d.isPageStable(page)
	if err == nil && isStable {
		// Page is already stable, no navigation happening
		return nil
	}

	// Check if navigation is actually in progress by monitoring for a short period
	navigationDetected, err := d.detectNavigationInProgress(page, 2*time.Second)
	if err != nil {
		return fmt.Errorf("failed to detect navigation state: %w", err)
	}

	if !navigationDetected {
		// No navigation detected, check if page is stable now
		isStable, err := d.isPageStable(page)
		if err == nil && isStable {
			return nil
		}
		// If we can't determine stability, proceed with waiting
	}

	// Navigation is in progress, wait for it to complete
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
	defer cancel()

	// Wait for navigation with timeout
	done := make(chan error, 1)
	go func() {
		defer func() {
			if r := recover(); r != nil {
				done <- fmt.Errorf("navigation wait panicked: %v", r)
			}
		}()

		// Wait for navigation event
		page.WaitNavigation(proto.PageLifecycleEventNameLoad)()

		// Wait for the page to be fully loaded
		err := page.WaitLoad()
		done <- err
	}()

	select {
	case err := <-done:
		if err != nil {
			return fmt.Errorf("navigation wait failed: %w", err)
		}
		return nil
	case <-ctx.Done():
		// Timeout occurred, check if page is now stable
		isStable, err := d.isPageStable(page)
		if err == nil && isStable {
			// Page is stable, consider navigation complete
			return nil
		}
		return fmt.Errorf("navigation wait timed out after %d seconds", timeout)
	}
}

// getPageSource returns the entire source code of a page
func (d *Daemon) getPageSource(tabID string, timeout int) (string, error) {
	page, err := d.getTab(tabID)
	if err != nil {
		return "", err
	}

	if timeout > 0 {
		// Use timeout for getting page source
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan struct {
			html string
			err  error
		}, 1)

		// Execute the HTML retrieval in a goroutine
		go func() {
			html, err := page.HTML()
			done <- struct {
				html string
				err  error
			}{html, err}
		}()

		// Wait for either completion or timeout
		select {
		case res := <-done:
			if res.err != nil {
				return "", fmt.Errorf("failed to get page HTML: %w", res.err)
			}
			return res.html, nil
		case <-ctx.Done():
			return "", fmt.Errorf("getting page source timed out after %d seconds", timeout)
		}
	} else {
		// No timeout
		html, err := page.HTML()
		if err != nil {
			return "", fmt.Errorf("failed to get page HTML: %w", err)
		}

		return html, nil
	}
}

// getElementHTML returns the HTML of an element at the specified selector
func (d *Daemon) getElementHTML(tabID, selector string, selectionTimeout int) (string, error) {
	page, err := d.getTab(tabID)
	if err != nil {
		return "", err
	}

	// Find the element with optional timeout
	var element *rod.Element
	if selectionTimeout > 0 {
		// Use timeout if specified
		element, err = page.Timeout(time.Duration(selectionTimeout) * time.Second).Element(selector)
		if err != nil {
			return "", fmt.Errorf("failed to find element (timeout after %ds): %w", selectionTimeout, err)
		}
	} else {
		// No timeout
		element, err = page.Element(selector)
		if err != nil {
			return "", fmt.Errorf("failed to find element: %w", err)
		}
	}

	// Get the HTML of the element
	html, err := element.HTML()
	if err != nil {
		return "", fmt.Errorf("failed to get element HTML: %w", err)
	}

	return html, nil
}

// fillFormField fills a form field with the specified value
func (d *Daemon) fillFormField(tabID, selector, value string, selectionTimeout, actionTimeout int) error {
	page, err := d.getTab(tabID)
	if err != nil {
		return err
	}

	// Find the element with optional timeout
	var element *rod.Element
	if selectionTimeout > 0 {
		// Use timeout if specified
		element, err = page.Timeout(time.Duration(selectionTimeout) * time.Second).Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find element (timeout after %ds): %w", selectionTimeout, err)
		}
	} else {
		// No timeout
		element, err = page.Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find element: %w", err)
		}
	}

	// Get the element type
	tagName, err := element.Eval(`() => this.tagName.toLowerCase()`)
	if err != nil {
		return fmt.Errorf("failed to get element type: %w", err)
	}

	// Get the element type attribute
	inputType, err := element.Eval(`() => this.type ? this.type.toLowerCase() : ''`)
	if err != nil {
		return fmt.Errorf("failed to get element type attribute: %w", err)
	}

	// Handle different input types
	tagNameStr := tagName.Value.String()
	typeStr := inputType.Value.String()

	// Handle checkbox and radio inputs
	if tagNameStr == "input" && (typeStr == "checkbox" || typeStr == "radio") {
		// Convert value to boolean
		checked := false
		if value == "true" || value == "1" || value == "yes" || value == "on" || value == "checked" {
			checked = true
		}

		// Set the checked state with optional timeout
		if actionTimeout > 0 {
			// Use timeout for the action
			ctx, cancel := context.WithTimeout(context.Background(), time.Duration(actionTimeout)*time.Second)
			defer cancel()

			// Create a channel to signal completion
			done := make(chan error, 1)

			// Execute the action in a goroutine
			go func() {
				_, err := element.Eval(fmt.Sprintf(`() => { this.checked = %t; return true; }`, checked))
				done <- err
			}()

			// Wait for either completion or timeout
			select {
			case err := <-done:
				if err != nil {
					return fmt.Errorf("failed to set checkbox state: %w", err)
				}
			case <-ctx.Done():
				return fmt.Errorf("setting checkbox state timed out after %d seconds", actionTimeout)
			}

			// Create a channel for the event trigger
			done = make(chan error, 1)

			// Trigger change event with timeout
			go func() {
				_, err := element.Eval(`() => {
					const event = new Event('change', { bubbles: true });
					this.dispatchEvent(event);
					return true;
				}`)
				done <- err
			}()

			// Wait for either completion or timeout
			select {
			case err := <-done:
				if err != nil {
					return fmt.Errorf("failed to trigger change event: %w", err)
				}
			case <-ctx.Done():
				return fmt.Errorf("triggering change event timed out after %d seconds", actionTimeout)
			}
		} else {
			// No timeout
			_, err := element.Eval(fmt.Sprintf(`() => { this.checked = %t; return true; }`, checked))
			if err != nil {
				return fmt.Errorf("failed to set checkbox state: %w", err)
			}

			// Trigger change event
			_, err = element.Eval(`() => {
				const event = new Event('change', { bubbles: true });
				this.dispatchEvent(event);
				return true;
			}`)
			if err != nil {
				return fmt.Errorf("failed to trigger change event: %w", err)
			}
		}

		return nil
	}

	// For regular text inputs
	if actionTimeout > 0 {
		// Use timeout for the action
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(actionTimeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan error, 1)

		// Clear the field first with timeout
		go func() {
			_ = element.SelectAllText()
			err := element.Input("")
			done <- err
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			if err != nil {
				return fmt.Errorf("failed to clear field: %w", err)
			}
		case <-ctx.Done():
			return fmt.Errorf("clearing field timed out after %d seconds", actionTimeout)
		}

		// Create a channel for the input action
		done = make(chan error, 1)

		// Input the value with timeout
		go func() {
			err := element.Input(value)
			done <- err
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			if err != nil {
				return fmt.Errorf("failed to input value: %w", err)
			}
		case <-ctx.Done():
			return fmt.Errorf("inputting value timed out after %d seconds", actionTimeout)
		}
	} else {
		// No timeout
		// Clear the field first
		_ = element.SelectAllText()
		err = element.Input("")
		if err != nil {
			return fmt.Errorf("failed to clear field: %w", err)
		}

		// Input the value
		err = element.Input(value)
		if err != nil {
			return fmt.Errorf("failed to input value: %w", err)
		}
	}

	return nil
}

// uploadFile uploads a file to a file input element
func (d *Daemon) uploadFile(tabID, selector, filePath string, selectionTimeout, actionTimeout int) error {
	page, err := d.getTab(tabID)
	if err != nil {
		return err
	}

	// Find the element with optional timeout
	var element *rod.Element
	if selectionTimeout > 0 {
		// Use timeout if specified
		element, err = page.Timeout(time.Duration(selectionTimeout) * time.Second).Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find file input element (timeout after %ds): %w", selectionTimeout, err)
		}
	} else {
		// No timeout
		element, err = page.Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find file input element: %w", err)
		}
	}

	// Set the file with optional timeout
	if actionTimeout > 0 {
		// Use timeout for the action
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(actionTimeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan error, 1)

		// Execute the action in a goroutine
		go func() {
			err := element.SetFiles([]string{filePath})
			done <- err
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			if err != nil {
				return fmt.Errorf("failed to set file: %w", err)
			}
		case <-ctx.Done():
			return fmt.Errorf("setting file timed out after %d seconds", actionTimeout)
		}
	} else {
		// No timeout
		err = element.SetFiles([]string{filePath})
		if err != nil {
			return fmt.Errorf("failed to set file: %w", err)
		}
	}

	return nil
}

// submitForm submits a form
func (d *Daemon) submitForm(tabID, selector string, selectionTimeout, actionTimeout int) error {
	page, err := d.getTab(tabID)
	if err != nil {
		return err
	}

	// Find the element with optional timeout
	var form *rod.Element
	if selectionTimeout > 0 {
		// Use timeout if specified
		form, err = page.Timeout(time.Duration(selectionTimeout) * time.Second).Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find form element (timeout after %ds): %w", selectionTimeout, err)
		}
	} else {
		// No timeout
		form, err = page.Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find form element: %w", err)
		}
	}

	// Get the current URL to detect navigation
	currentURL := page.MustInfo().URL

	// Create a context for navigation timeout
	var ctx context.Context
	var cancel context.CancelFunc

	// Submit the form with optional timeout
	if actionTimeout > 0 {
		// Use timeout for the action
		submitCtx, submitCancel := context.WithTimeout(context.Background(), time.Duration(actionTimeout)*time.Second)
		defer submitCancel()

		// Create a channel to signal completion
		done := make(chan error, 1)

		// Execute the action in a goroutine
		go func() {
			_, err := form.Eval(`() => { try { this.submit(); return true; } catch(e) { return false; } }`)
			done <- err
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			if err != nil {
				// Log the error but continue
				fmt.Printf("Warning: error during form submission: %v\n", err)
			}
		case <-submitCtx.Done():
			return fmt.Errorf("form submission timed out after %d seconds", actionTimeout)
		}

		// Wait for navigation to complete (with the same timeout)
		ctx, cancel = context.WithTimeout(context.Background(), time.Duration(actionTimeout)*time.Second)
	} else {
		// No timeout for submission
		try := func() (bool, error) {
			_, err := form.Eval(`() => { try { this.submit(); return true; } catch(e) { return false; } }`)
			return err == nil, err
		}

		// Try to submit the form, but don't fail if it's already been submitted
		_, err = try()
		if err != nil {
			// Log the error but continue
			fmt.Printf("Warning: error during form submission: %v\n", err)
		}

		// Wait for navigation to complete (with default timeout)
		ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
	}
	defer cancel()

	// Wait for the page to navigate away from the current URL
	waitNav := func() error {
		for {
			select {
			case <-ctx.Done():
				return ctx.Err()
			case <-time.After(100 * time.Millisecond):
				// Check if the page has navigated
				try := func() (string, error) {
					info, err := page.Info()
					if err != nil {
						return "", err
					}
					return info.URL, nil
				}

				newURL, err := try()
				if err != nil {
					// Page might be navigating, wait a bit more
					continue
				}

				if newURL != currentURL {
					// Navigation completed
					return nil
				}
			}
		}
	}

	// Wait for navigation but don't fail if it times out
	err = waitNav()
	if err != nil {
		// Log the error but don't fail
		fmt.Printf("Warning: navigation after form submission may not have completed: %v\n", err)
	}

	return nil
}

// clickElement clicks on an element
func (d *Daemon) clickElement(tabID, selector string, selectionTimeout, actionTimeout int) error {
	page, err := d.getTab(tabID)
	if err != nil {
		return err
	}

	// Find the element with optional timeout
	var element *rod.Element
	if selectionTimeout > 0 {
		// Use timeout if specified
		element, err = page.Timeout(time.Duration(selectionTimeout) * time.Second).Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find element (timeout after %ds): %w", selectionTimeout, err)
		}
	} else {
		// No timeout
		element, err = page.Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find element: %w", err)
		}
	}

	// Make sure the element is visible and scrolled into view
	err = element.ScrollIntoView()
	if err != nil {
		return fmt.Errorf("failed to scroll element into view: %w", err)
	}

	// Click the element with optional timeout
	if actionTimeout > 0 {
		// Use timeout for the click action
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(actionTimeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan error, 1)

		// Execute the click in a goroutine
		go func() {
			err := element.Click(proto.InputMouseButtonLeft, 1) // 1 click
			done <- err
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			if err != nil {
				return fmt.Errorf("failed to click element: %w", err)
			}
		case <-ctx.Done():
			return fmt.Errorf("click action timed out after %d seconds", actionTimeout)
		}
	} else {
		// No timeout
		err = element.Click(proto.InputMouseButtonLeft, 1) // 1 click
		if err != nil {
			return fmt.Errorf("failed to click element: %w", err)
		}
	}

	// Wait a moment for any navigation to start
	time.Sleep(100 * time.Millisecond)

	// Wait for any potential page load or DOM changes
	err = page.WaitStable(1 * time.Second)
	if err != nil {
		// This is not a critical error, so we'll just log it
		log.Printf("Warning: page not stable after click: %v", err)
	}

	return nil
}

// evalJS executes JavaScript code in a tab and returns the result
func (d *Daemon) evalJS(tabID, jsCode string, timeout int) (string, error) {
	page, err := d.getTab(tabID)
	if err != nil {
		return "", err
	}

	// Create a comprehensive wrapper that handles both expressions and statements
	// and properly formats the result
	wrappedCode := `() => {
		var result;
		try {
			// Try to evaluate as an expression first
			result = eval(` + "`" + jsCode + "`" + `);
		} catch(e) {
			// If that fails, try to execute as statements
			try {
				eval(` + "`" + jsCode + "`" + `);
				result = undefined;
			} catch(e2) {
				throw e; // Re-throw the original error
			}
		}

		// Format the result for return
		if (typeof result === 'undefined') return 'undefined';
		if (result === null) return 'null';
		if (typeof result === 'string') return result;
		if (typeof result === 'number' || typeof result === 'boolean') return String(result);
		try {
			return JSON.stringify(result);
		} catch(e) {
			return String(result);
		}
	}`

	// Execute the wrapped JavaScript code with timeout
	if timeout > 0 {
		// Use timeout for the JavaScript execution
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan struct {
			result string
			err    error
		}, 1)

		// Execute the JavaScript in a goroutine
		go func() {
			result, err := page.Eval(wrappedCode)
			var resultStr string
			if err == nil {
				// Convert the result to a string representation
				if result.Value.Nil() {
					resultStr = "null"
				} else {
					resultStr = result.Value.String()
				}
			}
			done <- struct {
				result string
				err    error
			}{resultStr, err}
		}()

		// Wait for either completion or timeout
		select {
		case res := <-done:
			if res.err != nil {
				return "", fmt.Errorf("failed to execute JavaScript: %w", res.err)
			}
			return res.result, nil
		case <-ctx.Done():
			return "", fmt.Errorf("JavaScript execution timed out after %d seconds", timeout)
		}
	} else {
		// No timeout
		result, err := page.Eval(wrappedCode)
		if err != nil {
			return "", fmt.Errorf("failed to execute JavaScript: %w", err)
		}

		// Convert the result to a string representation
		if result.Value.Nil() {
			return "null", nil
		}

		return result.Value.String(), nil
	}
}

// takeScreenshot takes a screenshot of a tab and saves it to a file
func (d *Daemon) takeScreenshot(tabID, outputPath string, fullPage bool, timeout int) error {
	page, err := d.getTab(tabID)
	if err != nil {
		return err
	}

	if timeout > 0 {
		// Use timeout for taking screenshot
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan error, 1)

		// Execute the screenshot in a goroutine
		go func() {
			// Take screenshot and save it
			screenshotBytes, err := page.Screenshot(fullPage, &proto.PageCaptureScreenshot{
				Format: proto.PageCaptureScreenshotFormatPng,
			})

			if err != nil {
				done <- fmt.Errorf("failed to capture screenshot: %w", err)
				return
			}

			// Write the screenshot to file
			err = os.WriteFile(outputPath, screenshotBytes, 0644)
			if err != nil {
				done <- fmt.Errorf("failed to save screenshot to %s: %w", outputPath, err)
				return
			}

			done <- nil
		}()

		// Wait for either completion or timeout
		select {
		case err := <-done:
			if err != nil {
				return fmt.Errorf("failed to save screenshot: %w", err)
			}
			return nil
		case <-ctx.Done():
			return fmt.Errorf("taking screenshot timed out after %d seconds", timeout)
		}
	} else {
		// No timeout - take screenshot directly
		screenshotBytes, err := page.Screenshot(fullPage, &proto.PageCaptureScreenshot{
			Format: proto.PageCaptureScreenshotFormatPng,
		})

		if err != nil {
			return fmt.Errorf("failed to capture screenshot: %w", err)
		}

		// Write the screenshot to file
		err = os.WriteFile(outputPath, screenshotBytes, 0644)
		if err != nil {
			return fmt.Errorf("failed to save screenshot to %s: %w", outputPath, err)
		}

		return nil
	}
}

// switchToIframe switches the context to an iframe for subsequent commands
func (d *Daemon) switchToIframe(tabID, selector string, timeout int) error {
	d.debugLog("Switching to iframe: selector=%s, tab=%s, timeout=%d", selector, tabID, timeout)

	// Get the main page first (not iframe context)
	actualTabID, err := d.getTabID(tabID)
	if err != nil {
		d.debugLog("Failed to get tab ID: %v", err)
		return err
	}

	d.mu.Lock()
	defer d.mu.Unlock()

	// Get the main page (bypass iframe context)
	mainPage, exists := d.tabs[actualTabID]
	if !exists {
		d.debugLog("Tab %s not in cache, trying to find it", actualTabID)
		// Try to find it
		mainPage, err = d.findPageByID(actualTabID)
		if err != nil {
			d.debugLog("Failed to find tab %s: %v", actualTabID, err)
			return err
		}
		if mainPage == nil {
			d.debugLog("Tab %s not found", actualTabID)
			return fmt.Errorf("tab not found: %s", actualTabID)
		}
		d.tabs[actualTabID] = mainPage
	}

	d.debugLog("Found main page for tab %s, looking for iframe element", actualTabID)

	// Find the iframe element with timeout
	var iframeElement *rod.Element
	if timeout > 0 {
		// Use timeout context for finding the iframe element
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan struct {
			element *rod.Element
			err     error
		}, 1)

		// Execute the element search in a goroutine
		go func() {
			defer func() {
				if r := recover(); r != nil {
					done <- struct {
						element *rod.Element
						err     error
					}{nil, fmt.Errorf("iframe element search panicked: %v", r)}
				}
			}()

			element, err := mainPage.Timeout(time.Duration(timeout) * time.Second).Element(selector)
			done <- struct {
				element *rod.Element
				err     error
			}{element, err}
		}()

		// Wait for either completion or timeout
		select {
		case result := <-done:
			iframeElement = result.element
			err = result.err
		case <-ctx.Done():
			d.debugLog("Iframe element search timed out after %d seconds", timeout)
			return fmt.Errorf("failed to find iframe element (timeout after %ds): %s", timeout, selector)
		}
	} else {
		// No timeout
		iframeElement, err = mainPage.Element(selector)
	}

	if err != nil {
		d.debugLog("Failed to find iframe element: %v", err)
		return fmt.Errorf("failed to find iframe element: %w", err)
	}

	d.debugLog("Found iframe element, getting frame context")

	// Get the iframe's page context with timeout
	var iframePage *rod.Page
	if timeout > 0 {
		// Use timeout context for getting the frame
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		// Create a channel to signal completion
		done := make(chan struct {
			page *rod.Page
			err  error
		}, 1)

		// Execute the frame access in a goroutine
		go func() {
			defer func() {
				if r := recover(); r != nil {
					done <- struct {
						page *rod.Page
						err  error
					}{nil, fmt.Errorf("iframe frame access panicked: %v", r)}
				}
			}()

			page, err := iframeElement.Frame()
			done <- struct {
				page *rod.Page
				err  error
			}{page, err}
		}()

		// Wait for either completion or timeout
		select {
		case result := <-done:
			iframePage = result.page
			err = result.err
		case <-ctx.Done():
			d.debugLog("Iframe frame access timed out after %d seconds", timeout)
			return fmt.Errorf("failed to get iframe context (timeout after %ds)", timeout)
		}
	} else {
		// No timeout
		iframePage, err = iframeElement.Frame()
	}

	if err != nil {
		d.debugLog("Failed to get iframe context: %v", err)
		return fmt.Errorf("failed to get iframe context: %w", err)
	}

	// Store the iframe page context
	d.iframePages[actualTabID] = iframePage
	d.debugLog("Successfully switched to iframe context for tab %s", actualTabID)

	return nil
}

// switchToMain switches back to the main page context
func (d *Daemon) switchToMain(tabID string) error {
	d.debugLog("Switching back to main context: tab=%s", tabID)

	// Get the tab ID to use (may be the current tab)
	actualTabID, err := d.getTabID(tabID)
	if err != nil {
		d.debugLog("Failed to get tab ID: %v", err)
		return err
	}

	d.mu.Lock()
	defer d.mu.Unlock()

	// Check if there was an iframe context to remove
	if _, exists := d.iframePages[actualTabID]; exists {
		d.debugLog("Removing iframe context for tab %s", actualTabID)
		// Remove the iframe context for this tab
		delete(d.iframePages, actualTabID)
	} else {
		d.debugLog("No iframe context found for tab %s", actualTabID)
	}

	d.debugLog("Successfully switched back to main context for tab %s", actualTabID)
	return nil
}

// handleFileUpload handles file upload requests from clients
func (d *Daemon) handleFileUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Parse multipart form (32MB max memory)
	err := r.ParseMultipartForm(32 << 20)
	if err != nil {
		http.Error(w, "Failed to parse multipart form", http.StatusBadRequest)
		return
	}

	// Get the uploaded file
	file, header, err := r.FormFile("file")
	if err != nil {
		http.Error(w, "Failed to get uploaded file", http.StatusBadRequest)
		return
	}
	defer file.Close()

	// Get the target path (optional, defaults to /tmp/)
	targetPath := r.FormValue("path")
	if targetPath == "" {
		targetPath = "/tmp/" + header.Filename
	}

	// Create the target file
	targetFile, err := os.Create(targetPath)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to create target file: %v", err), http.StatusInternalServerError)
		return
	}
	defer targetFile.Close()

	// Copy the uploaded file to the target location
	_, err = io.Copy(targetFile, file)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to save file: %v", err), http.StatusInternalServerError)
		return
	}

	// Return success response
	response := Response{
		Success: true,
		Data: map[string]interface{}{
			"filename":    header.Filename,
			"size":        header.Size,
			"target_path": targetPath,
		},
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// handleFileDownload handles file download requests from clients
func (d *Daemon) handleFileDownload(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Get the file path from query parameter
	filePath := r.URL.Query().Get("path")
	if filePath == "" {
		http.Error(w, "File path is required", http.StatusBadRequest)
		return
	}

	// Check if file exists and get info
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			http.Error(w, "File not found", http.StatusNotFound)
		} else {
			http.Error(w, fmt.Sprintf("Failed to access file: %v", err), http.StatusInternalServerError)
		}
		return
	}

	// Open the file
	file, err := os.Open(filePath)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to open file: %v", err), http.StatusInternalServerError)
		return
	}
	defer file.Close()

	// Set headers for file download
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileInfo.Name()))
	w.Header().Set("Content-Length", strconv.FormatInt(fileInfo.Size(), 10))

	// Stream the file to the client
	_, err = io.Copy(w, file)
	if err != nil {
		log.Printf("Error streaming file to client: %v", err)
	}
}

// setupConsoleLogging sets up console log capture for a tab
func (d *Daemon) setupConsoleLogging(tabID string, page *rod.Page) {
	// Initialize console logs for this tab
	d.consoleLogs[tabID] = make([]ConsoleLog, 0)

	// Listen for console events
	go page.EachEvent(func(e *proto.RuntimeConsoleAPICalled) {
		d.mu.Lock()
		defer d.mu.Unlock()

		// Convert console level
		level := string(e.Type)

		// Build message from arguments
		var message string
		for i, arg := range e.Args {
			if i > 0 {
				message += " "
			}
			// Handle different argument types
			if !arg.Value.Nil() {
				message += arg.Value.String()
			} else if arg.Description != "" {
				message += arg.Description
			} else {
				message += "[object]"
			}
		}

		// Create console log entry
		logEntry := ConsoleLog{
			Level:     level,
			Message:   message,
			Timestamp: time.Now(),
			Source:    "", // Could be enhanced with stack trace info
		}

		// Add to console logs (keep last 1000 entries per tab)
		logs := d.consoleLogs[tabID]
		logs = append(logs, logEntry)
		if len(logs) > 1000 {
			logs = logs[1:] // Remove oldest entry
		}
		d.consoleLogs[tabID] = logs
	})()
}

// getConsoleLogs retrieves console logs for a tab
func (d *Daemon) getConsoleLogs(tabID string, clear bool) ([]ConsoleLog, error) {
	d.mu.Lock()
	defer d.mu.Unlock()

	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return nil, fmt.Errorf("no tab specified and no current tab available")
	}

	// Check if tab exists
	if _, exists := d.tabs[tabID]; !exists {
		return nil, fmt.Errorf("tab not found: %s", tabID)
	}

	// Get logs for this tab
	logs, exists := d.consoleLogs[tabID]
	if !exists {
		logs = make([]ConsoleLog, 0)
	}

	// Clear logs if requested
	if clear {
		d.consoleLogs[tabID] = make([]ConsoleLog, 0)
	}

	return logs, nil
}

// executeConsoleCommand executes a command in the browser console
func (d *Daemon) executeConsoleCommand(tabID, command string, timeout int) (string, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return "", fmt.Errorf("no tab specified and no current tab available")
	}

	// Execute the command as JavaScript and return the result
	// This is similar to evalJS but specifically for console commands
	return d.evalJS(tabID, command, timeout)
}

// ElementCheckResult represents the result of an element check
type ElementCheckResult struct {
	Exists   bool `json:"exists"`
	Visible  bool `json:"visible,omitempty"`
	Enabled  bool `json:"enabled,omitempty"`
	Focused  bool `json:"focused,omitempty"`
	Selected bool `json:"selected,omitempty"`
	Count    int  `json:"count,omitempty"`
}

// MultipleExtractionResult represents the result of extracting from multiple selectors
type MultipleExtractionResult struct {
	Results map[string]interface{} `json:"results"`
	Errors  map[string]string      `json:"errors,omitempty"`
}

// LinkInfo represents information about a link
type LinkInfo struct {
	Href   string `json:"href"`
	Text   string `json:"text"`
	Title  string `json:"title,omitempty"`
	Target string `json:"target,omitempty"`
}

// LinksExtractionResult represents the result of extracting links
type LinksExtractionResult struct {
	Links []LinkInfo `json:"links"`
	Count int        `json:"count"`
}

// TableExtractionResult represents the result of extracting table data
type TableExtractionResult struct {
	Headers []string            `json:"headers,omitempty"`
	Rows    [][]string          `json:"rows"`
	Data    []map[string]string `json:"data,omitempty"` // Only if headers are included
	Count   int                 `json:"count"`
}

// TextExtractionResult represents the result of extracting text
type TextExtractionResult struct {
	Text    string   `json:"text"`
	Matches []string `json:"matches,omitempty"` // If pattern was used
	Count   int      `json:"count"`             // Number of elements matched
}

// checkElement checks various states of an element
func (d *Daemon) checkElement(tabID, selector, checkType string, timeout int) (*ElementCheckResult, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return nil, fmt.Errorf("no tab specified and no current tab available")
	}

	page, exists := d.tabs[tabID]
	if !exists {
		return nil, fmt.Errorf("tab %s not found", tabID)
	}

	// Check if we're in iframe mode for this tab
	if iframePage, inIframe := d.iframePages[tabID]; inIframe {
		page = iframePage
	}

	result := &ElementCheckResult{}

	// First check if element exists
	elements, err := page.Elements(selector)
	if err != nil {
		// If we can't find elements, it means they don't exist
		result.Exists = false
		return result, nil
	}

	result.Exists = len(elements) > 0
	result.Count = len(elements)

	// If no elements exist, return early
	if !result.Exists {
		return result, nil
	}

	// For additional checks, use the first element
	element := elements[0]

	switch checkType {
	case "exists":
		// Already handled above
	case "visible":
		visible, err := element.Visible()
		if err != nil {
			return nil, fmt.Errorf("failed to check visibility: %w", err)
		}
		result.Visible = visible
	case "enabled":
		// Check if element is enabled (not disabled)
		disabled, err := element.Attribute("disabled")
		if err != nil {
			return nil, fmt.Errorf("failed to check enabled state: %w", err)
		}
		result.Enabled = disabled == nil
	case "focused":
		// Check if element is focused
		jsCode := fmt.Sprintf("document.activeElement === document.querySelector('%s')", selector)
		focusResult, err := page.Eval(jsCode)
		if err != nil {
			return nil, fmt.Errorf("failed to check focus state: %w", err)
		}
		result.Focused = focusResult.Value.Bool()
	case "selected":
		// Check if element is selected (for checkboxes, radio buttons, options)
		selected, err := element.Attribute("selected")
		if err == nil && selected != nil {
			result.Selected = true
		} else {
			// Also check 'checked' attribute for checkboxes and radio buttons
			checked, err := element.Attribute("checked")
			if err == nil && checked != nil {
				result.Selected = true
			} else {
				result.Selected = false
			}
		}
	case "all":
		// Check all states
		visible, _ := element.Visible()
		result.Visible = visible

		disabled, _ := element.Attribute("disabled")
		result.Enabled = disabled == nil

		jsCode := fmt.Sprintf("document.activeElement === document.querySelector('%s')", selector)
		focusResult, _ := page.Eval(jsCode)
		if focusResult != nil {
			result.Focused = focusResult.Value.Bool()
		}

		selected, _ := element.Attribute("selected")
		if selected != nil {
			result.Selected = true
		} else {
			checked, _ := element.Attribute("checked")
			result.Selected = checked != nil
		}
	default:
		return nil, fmt.Errorf("unknown check type: %s", checkType)
	}

	return result, nil
}

// getElementAttributes gets attributes, properties, and computed styles of an element
func (d *Daemon) getElementAttributes(tabID, selector, attributes string, timeout int) (map[string]interface{}, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return nil, fmt.Errorf("no tab specified and no current tab available")
	}

	page, exists := d.tabs[tabID]
	if !exists {
		return nil, fmt.Errorf("tab %s not found", tabID)
	}

	// Check if we're in iframe mode for this tab
	if iframePage, inIframe := d.iframePages[tabID]; inIframe {
		page = iframePage
	}

	// Find the element with timeout
	var element *rod.Element
	if timeout > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		var err error
		element, err = page.Context(ctx).Element(selector)
		if err != nil {
			return nil, fmt.Errorf("element not found: %w", err)
		}
	} else {
		var err error
		element, err = page.Element(selector)
		if err != nil {
			return nil, fmt.Errorf("element not found: %w", err)
		}
	}

	result := make(map[string]interface{})

	if attributes == "all" {
		// Get all common attributes and properties
		commonAttrs := []string{
			"id", "class", "name", "type", "value", "href", "src", "alt", "title",
			"disabled", "checked", "selected", "readonly", "required", "placeholder",
			"data-*", "aria-*",
		}

		// Get HTML attributes
		for _, attr := range commonAttrs {
			if attr == "data-*" || attr == "aria-*" {
				// Skip wildcard attributes for now
				continue
			}
			value, err := element.Attribute(attr)
			if err == nil && value != nil {
				result[attr] = *value
			}
		}

		// Get common properties via JavaScript
		jsCode := `
			(function(el) {
				return {
					tagName: el.tagName,
					textContent: el.textContent,
					innerHTML: el.innerHTML,
					outerHTML: el.outerHTML,
					offsetWidth: el.offsetWidth,
					offsetHeight: el.offsetHeight,
					scrollWidth: el.scrollWidth,
					scrollHeight: el.scrollHeight,
					clientWidth: el.clientWidth,
					clientHeight: el.clientHeight
				};
			})(arguments[0])
		`

		jsResult, err := element.Eval(jsCode)
		if err == nil {
			if props := jsResult.Value.Map(); props != nil {
				for key, value := range props {
					result[key] = value
				}
			}
		}

		// Get computed styles for common properties
		styleProps := []string{
			"display", "visibility", "opacity", "position", "top", "left", "width", "height",
			"margin", "padding", "border", "background-color", "color", "font-size", "font-family",
		}

		for _, prop := range styleProps {
			jsCode := fmt.Sprintf("getComputedStyle(arguments[0]).%s", prop)
			styleResult, err := element.Eval(jsCode)
			if err == nil {
				result["style_"+prop] = styleResult.Value.Str()
			}
		}
	} else {
		// Get specific attributes (comma-separated)
		attrList := []string{}
		if attributes != "" {
			// Split by comma and trim spaces
			for _, attr := range strings.Split(attributes, ",") {
				attrList = append(attrList, strings.TrimSpace(attr))
			}
		}

		for _, attr := range attrList {
			if strings.HasPrefix(attr, "style_") {
				// Get computed style
				styleProp := strings.TrimPrefix(attr, "style_")
				jsCode := fmt.Sprintf("getComputedStyle(arguments[0]).%s", styleProp)
				styleResult, err := element.Eval(jsCode)
				if err == nil {
					result[attr] = styleResult.Value.Str()
				}
			} else if strings.HasPrefix(attr, "prop_") {
				// Get JavaScript property
				propName := strings.TrimPrefix(attr, "prop_")
				jsCode := fmt.Sprintf("arguments[0].%s", propName)
				propResult, err := element.Eval(jsCode)
				if err == nil {
					result[attr] = propResult.Value.Raw
				}
			} else {
				// Get HTML attribute
				value, err := element.Attribute(attr)
				if err == nil && value != nil {
					result[attr] = *value
				}
			}
		}
	}

	return result, nil
}

// countElements counts the number of elements matching a selector
func (d *Daemon) countElements(tabID, selector string, timeout int) (int, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return 0, fmt.Errorf("no tab specified and no current tab available")
	}

	page, exists := d.tabs[tabID]
	if !exists {
		return 0, fmt.Errorf("tab %s not found", tabID)
	}

	// Check if we're in iframe mode for this tab
	if iframePage, inIframe := d.iframePages[tabID]; inIframe {
		page = iframePage
	}

	// Find elements with timeout
	var elements rod.Elements
	var err error

	if timeout > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		elements, err = page.Context(ctx).Elements(selector)
	} else {
		elements, err = page.Elements(selector)
	}

	if err != nil {
		// If we can't find elements, return 0 (not an error)
		return 0, nil
	}

	return len(elements), nil
}

// extractMultiple extracts data from multiple selectors in a single call
func (d *Daemon) extractMultiple(tabID, selectorsJSON string, timeout int) (*MultipleExtractionResult, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return nil, fmt.Errorf("no tab specified and no current tab available")
	}

	page, exists := d.tabs[tabID]
	if !exists {
		return nil, fmt.Errorf("tab %s not found", tabID)
	}

	// Check if we're in iframe mode for this tab
	if iframePage, inIframe := d.iframePages[tabID]; inIframe {
		page = iframePage
	}

	// Parse selectors JSON
	var selectors map[string]string
	if err := json.Unmarshal([]byte(selectorsJSON), &selectors); err != nil {
		return nil, fmt.Errorf("invalid selectors JSON: %w", err)
	}

	result := &MultipleExtractionResult{
		Results: make(map[string]interface{}),
		Errors:  make(map[string]string),
	}

	// Extract from each selector
	for key, selector := range selectors {
		var elements rod.Elements
		var err error

		if timeout > 0 {
			ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
			defer cancel()
			elements, err = page.Context(ctx).Elements(selector)
		} else {
			elements, err = page.Elements(selector)
		}

		if err != nil {
			result.Errors[key] = err.Error()
			continue
		}

		if len(elements) == 0 {
			result.Results[key] = nil
			continue
		}

		// Extract content from all matching elements
		var values []string
		for _, element := range elements {
			var value string
			var err error

			// Check if it's a form input element and get its value
			tagName, _ := element.Eval("() => this.tagName.toLowerCase()")

			if tagName.Value.Str() == "input" || tagName.Value.Str() == "textarea" || tagName.Value.Str() == "select" {
				// For form elements, get the value property
				valueProp, err := element.Property("value")
				if err == nil && valueProp.Str() != "" {
					value = valueProp.Str()
				} else {
					// Fallback to text content
					value, err = element.Text()
				}
			} else {
				// For non-form elements, get text content
				value, err = element.Text()
			}

			if err != nil {
				result.Errors[key] = fmt.Sprintf("failed to get content: %v", err)
				break
			}
			values = append(values, value)
		}

		if len(values) == 1 {
			result.Results[key] = values[0]
		} else {
			result.Results[key] = values
		}
	}

	return result, nil
}

// extractLinks extracts all links from the page with optional filtering
func (d *Daemon) extractLinks(tabID, containerSelector, hrefPattern, textPattern string, timeout int) (*LinksExtractionResult, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return nil, fmt.Errorf("no tab specified and no current tab available")
	}

	page, exists := d.tabs[tabID]
	if !exists {
		return nil, fmt.Errorf("tab %s not found", tabID)
	}

	// Check if we're in iframe mode for this tab
	if iframePage, inIframe := d.iframePages[tabID]; inIframe {
		page = iframePage
	}

	// Build selector for links
	linkSelector := "a[href]"
	if containerSelector != "" {
		linkSelector = containerSelector + " " + linkSelector
	}

	// Find all links
	var elements rod.Elements
	var err error

	if timeout > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()
		elements, err = page.Context(ctx).Elements(linkSelector)
	} else {
		elements, err = page.Elements(linkSelector)
	}

	if err != nil {
		return nil, fmt.Errorf("failed to find links: %w", err)
	}

	result := &LinksExtractionResult{
		Links: make([]LinkInfo, 0),
		Count: 0,
	}

	// Compile regex patterns if provided
	var hrefRegex, textRegex *regexp.Regexp
	if hrefPattern != "" {
		hrefRegex, err = regexp.Compile(hrefPattern)
		if err != nil {
			return nil, fmt.Errorf("invalid href pattern: %w", err)
		}
	}
	if textPattern != "" {
		textRegex, err = regexp.Compile(textPattern)
		if err != nil {
			return nil, fmt.Errorf("invalid text pattern: %w", err)
		}
	}

	// Extract link information
	for _, element := range elements {
		href, err := element.Attribute("href")
		if err != nil || href == nil {
			continue
		}

		text, err := element.Text()
		if err != nil {
			text = ""
		}

		// Apply filters
		if hrefRegex != nil && !hrefRegex.MatchString(*href) {
			continue
		}
		if textRegex != nil && !textRegex.MatchString(text) {
			continue
		}

		// Get additional attributes
		title, _ := element.Attribute("title")
		target, _ := element.Attribute("target")

		linkInfo := LinkInfo{
			Href: *href,
			Text: text,
		}
		if title != nil {
			linkInfo.Title = *title
		}
		if target != nil {
			linkInfo.Target = *target
		}

		result.Links = append(result.Links, linkInfo)
	}

	result.Count = len(result.Links)
	return result, nil
}

// extractTable extracts table data as structured JSON
func (d *Daemon) extractTable(tabID, selector string, includeHeaders bool, timeout int) (*TableExtractionResult, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return nil, fmt.Errorf("no tab specified and no current tab available")
	}

	page, exists := d.tabs[tabID]
	if !exists {
		return nil, fmt.Errorf("tab %s not found", tabID)
	}

	// Check if we're in iframe mode for this tab
	if iframePage, inIframe := d.iframePages[tabID]; inIframe {
		page = iframePage
	}

	// Find the table
	var table *rod.Element
	var err error

	if timeout > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()
		table, err = page.Context(ctx).Element(selector)
	} else {
		table, err = page.Element(selector)
	}

	if err != nil {
		return nil, fmt.Errorf("failed to find table: %w", err)
	}

	result := &TableExtractionResult{
		Rows:  make([][]string, 0),
		Count: 0,
	}

	// Extract headers if requested
	if includeHeaders {
		headerRows, err := table.Elements("thead tr, tr:first-child")
		if err == nil && len(headerRows) > 0 {
			headerCells, err := headerRows[0].Elements("th, td")
			if err == nil {
				headers := make([]string, 0)
				for _, cell := range headerCells {
					text, err := cell.Text()
					if err != nil {
						text = ""
					}
					headers = append(headers, strings.TrimSpace(text))
				}
				result.Headers = headers
			}
		}
	}

	// Extract all rows
	rows, err := table.Elements("tbody tr, tr")
	if err != nil {
		return nil, fmt.Errorf("failed to find table rows: %w", err)
	}

	// Skip header row if we extracted headers
	startIndex := 0
	if includeHeaders && len(result.Headers) > 0 {
		startIndex = 1
	}

	for i := startIndex; i < len(rows); i++ {
		cells, err := rows[i].Elements("td, th")
		if err != nil {
			continue
		}

		rowData := make([]string, 0)
		for _, cell := range cells {
			text, err := cell.Text()
			if err != nil {
				text = ""
			}
			rowData = append(rowData, strings.TrimSpace(text))
		}

		if len(rowData) > 0 {
			result.Rows = append(result.Rows, rowData)
		}
	}

	// Create structured data if headers are available
	if includeHeaders && len(result.Headers) > 0 {
		result.Data = make([]map[string]string, 0)
		for _, row := range result.Rows {
			rowMap := make(map[string]string)
			for i, header := range result.Headers {
				if i < len(row) {
					rowMap[header] = row[i]
				} else {
					rowMap[header] = ""
				}
			}
			result.Data = append(result.Data, rowMap)
		}
	}

	result.Count = len(result.Rows)
	return result, nil
}

// extractText extracts text content with optional pattern matching
func (d *Daemon) extractText(tabID, selector, pattern, extractType string, timeout int) (*TextExtractionResult, error) {
	// Use current tab if not specified
	if tabID == "" {
		tabID = d.currentTab
	}

	if tabID == "" {
		return nil, fmt.Errorf("no tab specified and no current tab available")
	}

	page, exists := d.tabs[tabID]
	if !exists {
		return nil, fmt.Errorf("tab %s not found", tabID)
	}

	// Check if we're in iframe mode for this tab
	if iframePage, inIframe := d.iframePages[tabID]; inIframe {
		page = iframePage
	}

	// Default extract type
	if extractType == "" {
		extractType = "textContent"
	}

	// Find elements
	var elements rod.Elements
	var err error

	if timeout > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()
		elements, err = page.Context(ctx).Elements(selector)
	} else {
		elements, err = page.Elements(selector)
	}

	if err != nil {
		return nil, fmt.Errorf("failed to find elements: %w", err)
	}

	result := &TextExtractionResult{
		Count: len(elements),
	}

	// Compile regex pattern if provided
	var textRegex *regexp.Regexp
	if pattern != "" {
		textRegex, err = regexp.Compile(pattern)
		if err != nil {
			return nil, fmt.Errorf("invalid text pattern: %w", err)
		}
	}

	// Extract text from all elements
	var allTexts []string
	for _, element := range elements {
		var text string

		switch extractType {
		case "text":
			text, err = element.Text()
		case "innerText":
			// Use JavaScript to get innerText
			jsResult, jsErr := element.Eval("() => this.innerText")
			if jsErr == nil && jsResult.Value.Str() != "" {
				text = jsResult.Value.Str()
			} else {
				text, err = element.Text() // Fallback
			}
		case "textContent":
			// Use JavaScript to get textContent
			jsResult, jsErr := element.Eval("() => this.textContent")
			if jsErr == nil && jsResult.Value.Str() != "" {
				text = jsResult.Value.Str()
			} else {
				text, err = element.Text() // Fallback
			}
		default:
			text, err = element.Text()
		}

		if err != nil {
			continue
		}

		allTexts = append(allTexts, text)
	}

	// Join all texts
	result.Text = strings.Join(allTexts, "\n")

	// Apply pattern matching if provided
	if textRegex != nil {
		matches := textRegex.FindAllString(result.Text, -1)
		result.Matches = matches
	}

	return result, nil
}

// FormField represents a form field with its properties
type FormField struct {
	Name        string            `json:"name"`
	Type        string            `json:"type"`
	Value       string            `json:"value"`
	Placeholder string            `json:"placeholder,omitempty"`
	Required    bool              `json:"required"`
	Disabled    bool              `json:"disabled"`
	ReadOnly    bool              `json:"readonly"`
	Selector    string            `json:"selector"`
	Label       string            `json:"label,omitempty"`
	Options     []FormFieldOption `json:"options,omitempty"` // For select/radio/checkbox
}

// FormFieldOption represents an option in a select, radio, or checkbox group
type FormFieldOption struct {
	Value    string `json:"value"`
	Text     string `json:"text"`
	Selected bool   `json:"selected"`
}

// FormAnalysisResult represents the result of analyzing a form
type FormAnalysisResult struct {
	Action     string      `json:"action,omitempty"`
	Method     string      `json:"method,omitempty"`
	Fields     []FormField `json:"fields"`
	FieldCount int         `json:"field_count"`
	CanSubmit  bool        `json:"can_submit"`
	SubmitText string      `json:"submit_text,omitempty"`
}

// InteractionItem represents a single interaction to perform
type InteractionItem struct {
	Selector string `json:"selector"`
	Action   string `json:"action"` // click, fill, select, check, uncheck
	Value    string `json:"value,omitempty"`
}

// InteractionResult represents the result of a single interaction
type InteractionResult struct {
	Selector string `json:"selector"`
	Action   string `json:"action"`
	Success  bool   `json:"success"`
	Error    string `json:"error,omitempty"`
}

// MultipleInteractionResult represents the result of multiple interactions
type MultipleInteractionResult struct {
	Results      []InteractionResult `json:"results"`
	SuccessCount int                 `json:"success_count"`
	ErrorCount   int                 `json:"error_count"`
	TotalCount   int                 `json:"total_count"`
}

// FormBulkFillResult represents the result of bulk form filling
type FormBulkFillResult struct {
	FilledFields []InteractionResult `json:"filled_fields"`
	SuccessCount int                 `json:"success_count"`
	ErrorCount   int                 `json:"error_count"`
	TotalCount   int                 `json:"total_count"`
}

// analyzeForm analyzes a form and returns detailed information about its fields
func (d *Daemon) analyzeForm(tabID, selector string, timeout int) (*FormAnalysisResult, error) {
	page, err := d.getTab(tabID)
	if err != nil {
		return nil, err
	}

	// Find the form element
	var form *rod.Element
	if timeout > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()
		form, err = page.Context(ctx).Element(selector)
	} else {
		form, err = page.Element(selector)
	}

	if err != nil {
		return nil, fmt.Errorf("failed to find form: %w", err)
	}

	result := &FormAnalysisResult{
		Fields: make([]FormField, 0),
	}

	// Get form action and method
	if action, err := form.Attribute("action"); err == nil && action != nil {
		result.Action = *action
	}
	if method, err := form.Attribute("method"); err == nil && method != nil {
		result.Method = *method
	} else {
		result.Method = "GET" // Default
	}

	// Find all form fields
	fieldSelectors := []string{
		"input", "textarea", "select", "button[type='submit']", "input[type='submit']",
	}

	for _, fieldSelector := range fieldSelectors {
		elements, err := form.Elements(fieldSelector)
		if err != nil {
			continue
		}

		for _, element := range elements {
			field := FormField{}

			// Get basic attributes
			if name, err := element.Attribute("name"); err == nil && name != nil {
				field.Name = *name
			}
			if id, err := element.Attribute("id"); err == nil && id != nil && field.Name == "" {
				field.Name = *id
			}

			if fieldType, err := element.Attribute("type"); err == nil && fieldType != nil {
				field.Type = *fieldType
			} else {
				// Get tag name if no type
				if tagName, err := element.Eval("() => this.tagName.toLowerCase()"); err == nil {
					field.Type = tagName.Value.Str()
				}
			}

			// Skip submit buttons for field analysis but note them for submission info
			if field.Type == "submit" {
				result.CanSubmit = true
				if value, err := element.Attribute("value"); err == nil && value != nil {
					result.SubmitText = *value
				} else if text, err := element.Text(); err == nil {
					result.SubmitText = text
				}
				continue
			}

			// Get current value
			if value, err := element.Attribute("value"); err == nil && value != nil {
				field.Value = *value
			}

			// Get placeholder
			if placeholder, err := element.Attribute("placeholder"); err == nil && placeholder != nil {
				field.Placeholder = *placeholder
			}

			// Get boolean attributes
			if required, err := element.Attribute("required"); err == nil && required != nil {
				field.Required = true
			}
			if disabled, err := element.Attribute("disabled"); err == nil && disabled != nil {
				field.Disabled = true
			}
			if readonly, err := element.Attribute("readonly"); err == nil && readonly != nil {
				field.ReadOnly = true
			}

			// Generate selector for this field
			if field.Name != "" {
				field.Selector = fmt.Sprintf("[name='%s']", field.Name)
			} else if id, err := element.Attribute("id"); err == nil && id != nil {
				field.Selector = fmt.Sprintf("#%s", *id)
			}

			// Try to find associated label
			if field.Name != "" {
				if label, err := form.Element(fmt.Sprintf("label[for='%s']", field.Name)); err == nil {
					if labelText, err := label.Text(); err == nil {
						field.Label = labelText
					}
				}
			}

			// Handle select options
			if field.Type == "select" {
				options, err := element.Elements("option")
				if err == nil {
					field.Options = make([]FormFieldOption, 0)
					for _, option := range options {
						opt := FormFieldOption{}
						if value, err := option.Attribute("value"); err == nil && value != nil {
							opt.Value = *value
						}
						if text, err := option.Text(); err == nil {
							opt.Text = text
						}
						if selected, err := option.Attribute("selected"); err == nil && selected != nil {
							opt.Selected = true
						}
						field.Options = append(field.Options, opt)
					}
				}
			}

			result.Fields = append(result.Fields, field)
		}
	}

	result.FieldCount = len(result.Fields)

	// Check if form can be submitted (has submit button or can be submitted via JS)
	if !result.CanSubmit {
		// Look for any button that might submit
		if buttons, err := form.Elements("button"); err == nil {
			for _, button := range buttons {
				if buttonType, err := button.Attribute("type"); err == nil && buttonType != nil {
					if *buttonType == "submit" || *buttonType == "" {
						result.CanSubmit = true
						if text, err := button.Text(); err == nil {
							result.SubmitText = text
						}
						break
					}
				}
			}
		}
	}

	return result, nil
}

// interactMultiple performs multiple interactions in sequence
func (d *Daemon) interactMultiple(tabID, interactionsJSON string, timeout int) (*MultipleInteractionResult, error) {
	page, err := d.getTab(tabID)
	if err != nil {
		return nil, err
	}

	// Parse interactions JSON
	var interactions []InteractionItem
	err = json.Unmarshal([]byte(interactionsJSON), &interactions)
	if err != nil {
		return nil, fmt.Errorf("failed to parse interactions JSON: %w", err)
	}

	result := &MultipleInteractionResult{
		Results:    make([]InteractionResult, 0),
		TotalCount: len(interactions),
	}

	// Perform each interaction
	for _, interaction := range interactions {
		interactionResult := InteractionResult{
			Selector: interaction.Selector,
			Action:   interaction.Action,
			Success:  false,
		}

		// Find the element without timeout to avoid context cancellation issues
		var element *rod.Element
		element, err = page.Element(interaction.Selector)

		if err != nil {
			interactionResult.Error = fmt.Sprintf("failed to find element: %v", err)
			result.Results = append(result.Results, interactionResult)
			result.ErrorCount++
			continue
		}

		// Perform the action
		switch interaction.Action {
		case "click":
			err = element.Click(proto.InputMouseButtonLeft, 1)
			// Retry once if context was canceled
			if err != nil && strings.Contains(err.Error(), "context canceled") {
				// Try to find element again and click
				element, err = page.Element(interaction.Selector)
				if err == nil {
					err = element.Click(proto.InputMouseButtonLeft, 1)
				}
			}
			if err != nil {
				interactionResult.Error = fmt.Sprintf("failed to click: %v", err)
			} else {
				interactionResult.Success = true
			}

		case "fill":
			// Clear field first
			err = element.SelectAllText()
			if err == nil {
				err = element.Input("")
			}
			if err == nil {
				err = element.Input(interaction.Value)
			}
			// Retry once if context was canceled
			if err != nil && strings.Contains(err.Error(), "context canceled") {
				// Try to find element again and fill
				element, err = page.Element(interaction.Selector)
				if err == nil {
					err = element.SelectAllText()
					if err == nil {
						err = element.Input("")
					}
					if err == nil {
						err = element.Input(interaction.Value)
					}
				}
			}
			if err != nil {
				interactionResult.Error = fmt.Sprintf("failed to fill: %v", err)
			} else {
				interactionResult.Success = true
			}

		case "select":
			// For select elements, use rod's built-in Select method
			// Try to select by text first (most common case)
			err = element.Select([]string{interaction.Value}, true, rod.SelectorTypeText)
			if err != nil {
				// If text selection failed, the value might be the actual option value
				// Try to find and select by matching option value using page.Eval to avoid element.Eval issues
				script := fmt.Sprintf(`(function(){ var el = document.querySelector("%s"); if(el) { el.value = "%s"; el.dispatchEvent(new Event('change', { bubbles: true })); } })()`, interaction.Selector, interaction.Value)
				_, jsErr := page.Eval(script)
				if jsErr == nil {
					// Verify the JavaScript selection worked by checking the element's value
					currentValue, err := element.Property("value")
					if err != nil {
						interactionResult.Error = fmt.Sprintf("failed to verify selection: %v", err)
					} else if currentValue.Str() == interaction.Value {
						interactionResult.Success = true
					} else {
						interactionResult.Error = fmt.Sprintf("failed to select option: %s (current value: %s)", interaction.Value, currentValue.Str())
					}
				} else {
					interactionResult.Error = fmt.Sprintf("failed to select option: %v", jsErr)
				}
			} else {
				interactionResult.Success = true
			}

		case "check":
			// Check if it's already checked
			checked, err := element.Property("checked")
			if err == nil && checked.Bool() {
				interactionResult.Success = true // Already checked
			} else {
				err = element.Click(proto.InputMouseButtonLeft, 1)
				// Retry once if context was canceled
				if err != nil && strings.Contains(err.Error(), "context canceled") {
					// Try to find element again and click
					element, err = page.Element(interaction.Selector)
					if err == nil {
						err = element.Click(proto.InputMouseButtonLeft, 1)
					}
				}
				if err != nil {
					interactionResult.Error = fmt.Sprintf("failed to check: %v", err)
				} else {
					interactionResult.Success = true
				}
			}

		case "uncheck":
			// Check if it's already unchecked
			checked, err := element.Property("checked")
			if err == nil && !checked.Bool() {
				interactionResult.Success = true // Already unchecked
			} else {
				err = element.Click(proto.InputMouseButtonLeft, 1)
				if err != nil {
					interactionResult.Error = fmt.Sprintf("failed to uncheck: %v", err)
				} else {
					interactionResult.Success = true
				}
			}

		default:
			interactionResult.Error = fmt.Sprintf("unknown action: %s", interaction.Action)
		}

		result.Results = append(result.Results, interactionResult)
		if interactionResult.Success {
			result.SuccessCount++
		} else {
			result.ErrorCount++
		}
	}

	return result, nil
}

// fillFormBulk fills multiple form fields in a single operation
func (d *Daemon) fillFormBulk(tabID, formSelector, fieldsJSON string, timeout int) (*FormBulkFillResult, error) {
	page, err := d.getTab(tabID)
	if err != nil {
		return nil, err
	}

	// Parse fields JSON
	var fields map[string]string
	err = json.Unmarshal([]byte(fieldsJSON), &fields)
	if err != nil {
		return nil, fmt.Errorf("failed to parse fields JSON: %w", err)
	}

	result := &FormBulkFillResult{
		FilledFields: make([]InteractionResult, 0),
		TotalCount:   len(fields),
	}

	// Find the form element if selector is provided
	var form *rod.Element
	if formSelector != "" {
		if timeout > 0 {
			ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
			form, err = page.Context(ctx).Element(formSelector)
			cancel()
		} else {
			form, err = page.Element(formSelector)
		}

		if err != nil {
			return nil, fmt.Errorf("failed to find form: %w", err)
		}
	}

	// Fill each field
	for fieldName, fieldValue := range fields {
		fieldResult := InteractionResult{
			Selector: fieldName,
			Action:   "fill",
			Success:  false,
		}

		// Try different selector strategies for the field
		var element *rod.Element
		var selectors []string

		// If we have a form, search within it first
		if form != nil {
			selectors = []string{
				fmt.Sprintf("[name='%s']", fieldName),
				fmt.Sprintf("#%s", fieldName),
				fmt.Sprintf("[id='%s']", fieldName),
				fieldName, // In case it's already a full selector
			}

			for _, selector := range selectors {
				if timeout > 0 {
					ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
					element, err = form.Context(ctx).Element(selector)
					// Don't cancel yet if element found - we need context for filling
					if err == nil {
						fieldResult.Selector = selector
						// Fill the field while context is still valid
						err = element.SelectAllText()
						if err == nil {
							err = element.Input("")
						}
						if err == nil {
							err = element.Input(fieldValue)
						}
						cancel() // Now we can cancel
						break
					}
					cancel() // Cancel if element not found
				} else {
					element, err = form.Element(selector)
					if err == nil {
						fieldResult.Selector = selector
						// Fill the field
						err = element.SelectAllText()
						if err == nil {
							err = element.Input("")
						}
						if err == nil {
							err = element.Input(fieldValue)
						}
						break
					}
				}
			}
		}

		// If not found in form or no form, search in entire page
		if element == nil {
			// Generate selectors if not already done
			if selectors == nil {
				selectors = []string{
					fmt.Sprintf("[name='%s']", fieldName),
					fmt.Sprintf("#%s", fieldName),
					fmt.Sprintf("[id='%s']", fieldName),
					fieldName, // In case it's already a full selector
				}
			}

			for _, selector := range selectors {
				if timeout > 0 {
					ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
					element, err = page.Context(ctx).Element(selector)
					// Don't cancel yet - we need the context for filling
					if err == nil {
						fieldResult.Selector = selector
						// Fill the field while context is still valid
						err = element.SelectAllText()
						if err == nil {
							err = element.Input("")
						}
						if err == nil {
							err = element.Input(fieldValue)
						}
						cancel() // Now we can cancel
						break
					}
					cancel() // Cancel if element not found
				} else {
					element, err = page.Element(selector)
					if err == nil {
						fieldResult.Selector = selector
						// Fill the field
						err = element.SelectAllText()
						if err == nil {
							err = element.Input("")
						}
						if err == nil {
							err = element.Input(fieldValue)
						}
						break
					}
				}
			}
		}

		if element == nil {
			fieldResult.Error = fmt.Sprintf("failed to find field: %s", fieldName)
			result.FilledFields = append(result.FilledFields, fieldResult)
			result.ErrorCount++
			continue
		}

		if err != nil {
			fieldResult.Error = fmt.Sprintf("failed to fill field: %v", err)
			result.ErrorCount++
		} else {
			fieldResult.Success = true
			result.SuccessCount++
		}

		result.FilledFields = append(result.FilledFields, fieldResult)
	}

	return result, nil
}

// PageInfo represents page metadata and state information
type PageInfo struct {
	Title         string `json:"title"`
	URL           string `json:"url"`
	LoadingState  string `json:"loading_state"`
	ReadyState    string `json:"ready_state"`
	Referrer      string `json:"referrer"`
	Domain        string `json:"domain"`
	Protocol      string `json:"protocol"`
	Charset       string `json:"charset"`
	ContentType   string `json:"content_type"`
	LastModified  string `json:"last_modified"`
	CookieEnabled bool   `json:"cookie_enabled"`
	OnlineStatus  bool   `json:"online_status"`
}

// ViewportInfo represents viewport and scroll information
type ViewportInfo struct {
	Width            int     `json:"width"`
	Height           int     `json:"height"`
	ScrollX          int     `json:"scroll_x"`
	ScrollY          int     `json:"scroll_y"`
	ScrollWidth      int     `json:"scroll_width"`
	ScrollHeight     int     `json:"scroll_height"`
	ClientWidth      int     `json:"client_width"`
	ClientHeight     int     `json:"client_height"`
	DevicePixelRatio float64 `json:"device_pixel_ratio"`
	Orientation      string  `json:"orientation"`
}

// PerformanceMetrics represents page performance data
type PerformanceMetrics struct {
	NavigationStart      int64 `json:"navigation_start"`
	LoadEventEnd         int64 `json:"load_event_end"`
	DOMContentLoaded     int64 `json:"dom_content_loaded"`
	FirstPaint           int64 `json:"first_paint"`
	FirstContentfulPaint int64 `json:"first_contentful_paint"`
	LoadTime             int64 `json:"load_time"`
	DOMLoadTime          int64 `json:"dom_load_time"`
	ResourceCount        int   `json:"resource_count"`
	JSHeapSizeLimit      int64 `json:"js_heap_size_limit"`
	JSHeapSizeTotal      int64 `json:"js_heap_size_total"`
	JSHeapSizeUsed       int64 `json:"js_heap_size_used"`
}

// ContentCheck represents content verification results
type ContentCheck struct {
	Type           string   `json:"type"`
	ImagesLoaded   int      `json:"images_loaded,omitempty"`
	ImagesTotal    int      `json:"images_total,omitempty"`
	ScriptsLoaded  int      `json:"scripts_loaded,omitempty"`
	ScriptsTotal   int      `json:"scripts_total,omitempty"`
	StylesLoaded   int      `json:"styles_loaded,omitempty"`
	StylesTotal    int      `json:"styles_total,omitempty"`
	FormsPresent   int      `json:"forms_present,omitempty"`
	LinksPresent   int      `json:"links_present,omitempty"`
	IframesPresent int      `json:"iframes_present,omitempty"`
	HasErrors      bool     `json:"has_errors,omitempty"`
	ErrorCount     int      `json:"error_count,omitempty"`
	ErrorMessages  []string `json:"error_messages,omitempty"`
}

// getPageInfo retrieves comprehensive page metadata and state information
func (d *Daemon) getPageInfo(tabID string, timeout int) (*PageInfo, error) {
	d.debugLog("Getting page info for tab: %s with timeout: %d", tabID, timeout)

	page, err := d.getTab(tabID)
	if err != nil {
		return nil, fmt.Errorf("failed to get page: %v", err)
	}

	result := &PageInfo{}

	// Get basic page information using JavaScript
	jsCode := `
		(() => {
			return {
				title: document.title,
				url: window.location.href,
				readyState: document.readyState,
				referrer: document.referrer,
				domain: document.domain,
				protocol: window.location.protocol,
				charset: document.characterSet || document.charset,
				contentType: document.contentType,
				lastModified: document.lastModified,
				cookieEnabled: navigator.cookieEnabled,
				onlineStatus: navigator.onLine
			};
		})()
	`

	jsResult, err := page.Eval(jsCode)
	if err != nil {
		return nil, fmt.Errorf("failed to execute JavaScript: %v", err)
	}

	// Parse the JavaScript result
	if props := jsResult.Value.Map(); props != nil {
		if title, ok := props["title"]; ok && title.Str() != "" {
			result.Title = title.Str()
		}
		if url, ok := props["url"]; ok && url.Str() != "" {
			result.URL = url.Str()
		}
		if readyState, ok := props["readyState"]; ok && readyState.Str() != "" {
			result.ReadyState = readyState.Str()
		}
		if referrer, ok := props["referrer"]; ok && referrer.Str() != "" {
			result.Referrer = referrer.Str()
		}
		if domain, ok := props["domain"]; ok && domain.Str() != "" {
			result.Domain = domain.Str()
		}
		if protocol, ok := props["protocol"]; ok && protocol.Str() != "" {
			result.Protocol = protocol.Str()
		}
		if charset, ok := props["charset"]; ok && charset.Str() != "" {
			result.Charset = charset.Str()
		}
		if contentType, ok := props["contentType"]; ok && contentType.Str() != "" {
			result.ContentType = contentType.Str()
		}
		if lastModified, ok := props["lastModified"]; ok && lastModified.Str() != "" {
			result.LastModified = lastModified.Str()
		}
		if cookieEnabled, ok := props["cookieEnabled"]; ok {
			result.CookieEnabled = cookieEnabled.Bool()
		}
		if onlineStatus, ok := props["onlineStatus"]; ok {
			result.OnlineStatus = onlineStatus.Bool()
		}
	}

	// Determine loading state
	if result.ReadyState == "complete" {
		result.LoadingState = "complete"
	} else if result.ReadyState == "interactive" {
		result.LoadingState = "interactive"
	} else {
		result.LoadingState = "loading"
	}

	d.debugLog("Successfully retrieved page info for tab: %s", tabID)
	return result, nil
}

// getViewportInfo retrieves viewport and scroll information
func (d *Daemon) getViewportInfo(tabID string, timeout int) (*ViewportInfo, error) {
	d.debugLog("Getting viewport info for tab: %s with timeout: %d", tabID, timeout)

	page, err := d.getTab(tabID)
	if err != nil {
		return nil, fmt.Errorf("failed to get page: %v", err)
	}

	result := &ViewportInfo{}

	// Get viewport and scroll information using JavaScript
	jsCode := `
		(() => {
			return {
				width: window.innerWidth,
				height: window.innerHeight,
				scrollX: window.scrollX || window.pageXOffset,
				scrollY: window.scrollY || window.pageYOffset,
				scrollWidth: document.documentElement.scrollWidth,
				scrollHeight: document.documentElement.scrollHeight,
				clientWidth: document.documentElement.clientWidth,
				clientHeight: document.documentElement.clientHeight,
				devicePixelRatio: window.devicePixelRatio,
				orientation: screen.orientation ? screen.orientation.type : 'unknown'
			};
		})()
	`

	jsResult, err := page.Eval(jsCode)
	if err != nil {
		return nil, fmt.Errorf("failed to execute JavaScript: %v", err)
	}

	// Parse the JavaScript result
	if props := jsResult.Value.Map(); props != nil {
		if width, ok := props["width"]; ok {
			result.Width = int(width.Num())
		}
		if height, ok := props["height"]; ok {
			result.Height = int(height.Num())
		}
		if scrollX, ok := props["scrollX"]; ok {
			result.ScrollX = int(scrollX.Num())
		}
		if scrollY, ok := props["scrollY"]; ok {
			result.ScrollY = int(scrollY.Num())
		}
		if scrollWidth, ok := props["scrollWidth"]; ok {
			result.ScrollWidth = int(scrollWidth.Num())
		}
		if scrollHeight, ok := props["scrollHeight"]; ok {
			result.ScrollHeight = int(scrollHeight.Num())
		}
		if clientWidth, ok := props["clientWidth"]; ok {
			result.ClientWidth = int(clientWidth.Num())
		}
		if clientHeight, ok := props["clientHeight"]; ok {
			result.ClientHeight = int(clientHeight.Num())
		}
		if devicePixelRatio, ok := props["devicePixelRatio"]; ok {
			result.DevicePixelRatio = devicePixelRatio.Num()
		}
		if orientation, ok := props["orientation"]; ok && orientation.Str() != "" {
			result.Orientation = orientation.Str()
		}
	}

	d.debugLog("Successfully retrieved viewport info for tab: %s", tabID)
	return result, nil
}

// getPerformance retrieves page performance metrics
func (d *Daemon) getPerformance(tabID string, timeout int) (*PerformanceMetrics, error) {
	d.debugLog("Getting performance metrics for tab: %s with timeout: %d", tabID, timeout)

	page, err := d.getTab(tabID)
	if err != nil {
		return nil, fmt.Errorf("failed to get page: %v", err)
	}

	result := &PerformanceMetrics{}

	// Get performance metrics using JavaScript
	jsCode := `
		(() => {
			const perf = window.performance;
			const timing = perf.timing;
			const navigation = perf.navigation;
			const memory = perf.memory;

			// Get paint metrics if available
			let firstPaint = 0;
			let firstContentfulPaint = 0;
			if (perf.getEntriesByType) {
				const paintEntries = perf.getEntriesByType('paint');
				for (const entry of paintEntries) {
					if (entry.name === 'first-paint') {
						firstPaint = entry.startTime;
					} else if (entry.name === 'first-contentful-paint') {
						firstContentfulPaint = entry.startTime;
					}
				}
			}

			// Count resources
			let resourceCount = 0;
			if (perf.getEntriesByType) {
				resourceCount = perf.getEntriesByType('resource').length;
			}

			return {
				navigationStart: timing.navigationStart,
				loadEventEnd: timing.loadEventEnd,
				domContentLoaded: timing.domContentLoadedEventEnd,
				firstPaint: firstPaint,
				firstContentfulPaint: firstContentfulPaint,
				loadTime: timing.loadEventEnd - timing.navigationStart,
				domLoadTime: timing.domContentLoadedEventEnd - timing.navigationStart,
				resourceCount: resourceCount,
				jsHeapSizeLimit: memory ? memory.jsHeapSizeLimit : 0,
				jsHeapSizeTotal: memory ? memory.totalJSHeapSize : 0,
				jsHeapSizeUsed: memory ? memory.usedJSHeapSize : 0
			};
		})()
	`

	jsResult, err := page.Eval(jsCode)
	if err != nil {
		return nil, fmt.Errorf("failed to execute JavaScript: %v", err)
	}

	// Parse the JavaScript result
	if props := jsResult.Value.Map(); props != nil {
		if navigationStart, ok := props["navigationStart"]; ok {
			result.NavigationStart = int64(navigationStart.Num())
		}
		if loadEventEnd, ok := props["loadEventEnd"]; ok {
			result.LoadEventEnd = int64(loadEventEnd.Num())
		}
		if domContentLoaded, ok := props["domContentLoaded"]; ok {
			result.DOMContentLoaded = int64(domContentLoaded.Num())
		}
		if firstPaint, ok := props["firstPaint"]; ok {
			result.FirstPaint = int64(firstPaint.Num())
		}
		if firstContentfulPaint, ok := props["firstContentfulPaint"]; ok {
			result.FirstContentfulPaint = int64(firstContentfulPaint.Num())
		}
		if loadTime, ok := props["loadTime"]; ok {
			result.LoadTime = int64(loadTime.Num())
		}
		if domLoadTime, ok := props["domLoadTime"]; ok {
			result.DOMLoadTime = int64(domLoadTime.Num())
		}
		if resourceCount, ok := props["resourceCount"]; ok {
			result.ResourceCount = int(resourceCount.Num())
		}
		if jsHeapSizeLimit, ok := props["jsHeapSizeLimit"]; ok {
			result.JSHeapSizeLimit = int64(jsHeapSizeLimit.Num())
		}
		if jsHeapSizeTotal, ok := props["jsHeapSizeTotal"]; ok {
			result.JSHeapSizeTotal = int64(jsHeapSizeTotal.Num())
		}
		if jsHeapSizeUsed, ok := props["jsHeapSizeUsed"]; ok {
			result.JSHeapSizeUsed = int64(jsHeapSizeUsed.Num())
		}
	}

	d.debugLog("Successfully retrieved performance metrics for tab: %s", tabID)
	return result, nil
}

// checkContent verifies specific content types and loading states
func (d *Daemon) checkContent(tabID string, contentType string, timeout int) (*ContentCheck, error) {
	d.debugLog("Checking content type '%s' for tab: %s with timeout: %d", contentType, tabID, timeout)

	page, err := d.getTab(tabID)
	if err != nil {
		return nil, fmt.Errorf("failed to get page: %v", err)
	}

	result := &ContentCheck{
		Type: contentType,
	}

	var jsCode string

	switch contentType {
	case "images":
		jsCode = `
			(() => {
				const images = document.querySelectorAll('img');
				let loaded = 0;
				let total = images.length;

				images.forEach(img => {
					if (img.complete && img.naturalHeight !== 0) {
						loaded++;
					}
				});

				return {
					imagesLoaded: loaded,
					imagesTotal: total
				};
			})()
		`
	case "scripts":
		jsCode = `
			(() => {
				const scripts = document.querySelectorAll('script[src]');
				let loaded = 0;
				let total = scripts.length;

				scripts.forEach(script => {
					if (script.readyState === 'loaded' || script.readyState === 'complete' || !script.readyState) {
						loaded++;
					}
				});

				return {
					scriptsLoaded: loaded,
					scriptsTotal: total
				};
			})()
		`
	case "styles":
		jsCode = `
			(() => {
				const styles = document.querySelectorAll('link[rel="stylesheet"]');
				let loaded = 0;
				let total = styles.length;

				styles.forEach(style => {
					if (style.sheet) {
						loaded++;
					}
				});

				return {
					stylesLoaded: loaded,
					stylesTotal: total
				};
			})()
		`
	case "forms":
		jsCode = `
			(() => {
				return {
					formsPresent: document.querySelectorAll('form').length
				};
			})()
		`
	case "links":
		jsCode = `
			(() => {
				return {
					linksPresent: document.querySelectorAll('a[href]').length
				};
			})()
		`
	case "iframes":
		jsCode = `
			(() => {
				return {
					iframesPresent: document.querySelectorAll('iframe').length
				};
			})()
		`
	case "errors":
		jsCode = `
			(() => {
				const errors = [];

				// Check for JavaScript errors in console (if available)
				if (window.console && window.console.error) {
					// This is limited - we can't access console history
					// But we can check for common error indicators
				}

				// Check for broken images
				const brokenImages = Array.from(document.querySelectorAll('img')).filter(img =>
					!img.complete || img.naturalHeight === 0
				);

				if (brokenImages.length > 0) {
					errors.push('Broken images detected: ' + brokenImages.length);
				}

				// Check for missing stylesheets
				const brokenStyles = Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(link =>
					!link.sheet
				);

				if (brokenStyles.length > 0) {
					errors.push('Missing stylesheets detected: ' + brokenStyles.length);
				}

				return {
					hasErrors: errors.length > 0,
					errorCount: errors.length,
					errorMessages: errors
				};
			})()
		`
	default:
		return nil, fmt.Errorf("unknown content type: %s", contentType)
	}

	jsResult, err := page.Eval(jsCode)
	if err != nil {
		return nil, fmt.Errorf("failed to execute JavaScript: %v", err)
	}

	// Parse the JavaScript result
	if props := jsResult.Value.Map(); props != nil {
		if imagesLoaded, ok := props["imagesLoaded"]; ok {
			result.ImagesLoaded = int(imagesLoaded.Num())
		}
		if imagesTotal, ok := props["imagesTotal"]; ok {
			result.ImagesTotal = int(imagesTotal.Num())
		}
		if scriptsLoaded, ok := props["scriptsLoaded"]; ok {
			result.ScriptsLoaded = int(scriptsLoaded.Num())
		}
		if scriptsTotal, ok := props["scriptsTotal"]; ok {
			result.ScriptsTotal = int(scriptsTotal.Num())
		}
		if stylesLoaded, ok := props["stylesLoaded"]; ok {
			result.StylesLoaded = int(stylesLoaded.Num())
		}
		if stylesTotal, ok := props["stylesTotal"]; ok {
			result.StylesTotal = int(stylesTotal.Num())
		}
		if formsPresent, ok := props["formsPresent"]; ok {
			result.FormsPresent = int(formsPresent.Num())
		}
		if linksPresent, ok := props["linksPresent"]; ok {
			result.LinksPresent = int(linksPresent.Num())
		}
		if iframesPresent, ok := props["iframesPresent"]; ok {
			result.IframesPresent = int(iframesPresent.Num())
		}
		if hasErrors, ok := props["hasErrors"]; ok {
			result.HasErrors = hasErrors.Bool()
		}
		if errorCount, ok := props["errorCount"]; ok {
			result.ErrorCount = int(errorCount.Num())
		}
		if errorMessages, ok := props["errorMessages"]; ok {
			if arr := errorMessages.Arr(); arr != nil {
				for _, msg := range arr {
					if msg.Str() != "" {
						result.ErrorMessages = append(result.ErrorMessages, msg.Str())
					}
				}
			}
		}
	}

	d.debugLog("Successfully checked content type '%s' for tab: %s", contentType, tabID)
	return result, nil
}

// screenshotElement takes a screenshot of a specific element
func (d *Daemon) screenshotElement(tabID, selector, outputPath string, timeout int) error {
	d.debugLog("Taking element screenshot for tab: %s, selector: %s", tabID, selector)

	page, err := d.getTab(tabID)
	if err != nil {
		return err
	}

	// Find the element
	var element *rod.Element
	if timeout > 0 {
		element, err = page.Timeout(time.Duration(timeout) * time.Second).Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find element (timeout after %ds): %w", timeout, err)
		}
	} else {
		element, err = page.Element(selector)
		if err != nil {
			return fmt.Errorf("failed to find element: %w", err)
		}
	}

	// Scroll element into view
	err = element.ScrollIntoView()
	if err != nil {
		return fmt.Errorf("failed to scroll element into view: %w", err)
	}

	// Wait for element to be stable
	err = element.WaitStable(500 * time.Millisecond)
	if err != nil {
		d.debugLog("Warning: element not stable: %v", err)
	}

	// Take screenshot of the element
	screenshotBytes, err := element.Screenshot(proto.PageCaptureScreenshotFormatPng, 0)
	if err != nil {
		return fmt.Errorf("failed to capture element screenshot: %w", err)
	}

	// Write the screenshot to file
	err = os.WriteFile(outputPath, screenshotBytes, 0644)
	if err != nil {
		return fmt.Errorf("failed to save element screenshot to %s: %w", outputPath, err)
	}

	d.debugLog("Successfully captured element screenshot for tab: %s", tabID)
	return nil
}

// ScreenshotMetadata represents metadata for enhanced screenshots
type ScreenshotMetadata struct {
	Timestamp    string `json:"timestamp"`
	URL          string `json:"url"`
	Title        string `json:"title"`
	ViewportSize struct {
		Width  int `json:"width"`
		Height int `json:"height"`
	} `json:"viewport_size"`
	FullPage   bool   `json:"full_page"`
	FilePath   string `json:"file_path"`
	FileSize   int64  `json:"file_size"`
	Resolution struct {
		Width  int `json:"width"`
		Height int `json:"height"`
	} `json:"resolution"`
}

// screenshotEnhanced takes a screenshot with metadata
func (d *Daemon) screenshotEnhanced(tabID, outputPath string, fullPage bool, timeout int) (*ScreenshotMetadata, error) {
	d.debugLog("Taking enhanced screenshot for tab: %s", tabID)

	page, err := d.getTab(tabID)
	if err != nil {
		return nil, err
	}

	// Get page info for metadata
	pageInfo, err := page.Info()
	if err != nil {
		return nil, fmt.Errorf("failed to get page info: %w", err)
	}

	// Get viewport size
	viewport, err := page.Eval(`() => ({
		width: window.innerWidth,
		height: window.innerHeight
	})`)
	if err != nil {
		return nil, fmt.Errorf("failed to get viewport: %w", err)
	}

	viewportData := viewport.Value.Map()
	viewportWidth := int(viewportData["width"].Num())
	viewportHeight := int(viewportData["height"].Num())

	// Take screenshot with timeout handling
	var screenshotBytes []byte
	if timeout > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
		defer cancel()

		done := make(chan error, 1)
		go func() {
			bytes, err := page.Screenshot(fullPage, &proto.PageCaptureScreenshot{
				Format: proto.PageCaptureScreenshotFormatPng,
			})
			screenshotBytes = bytes
			done <- err
		}()

		select {
		case err := <-done:
			if err != nil {
				return nil, fmt.Errorf("failed to capture screenshot: %w", err)
			}
		case <-ctx.Done():
			return nil, fmt.Errorf("taking screenshot timed out after %d seconds", timeout)
		}
	} else {
		screenshotBytes, err = page.Screenshot(fullPage, &proto.PageCaptureScreenshot{
			Format: proto.PageCaptureScreenshotFormatPng,
		})
		if err != nil {
			return nil, fmt.Errorf("failed to capture screenshot: %w", err)
		}
	}

	// Write the screenshot to file
	err = os.WriteFile(outputPath, screenshotBytes, 0644)
	if err != nil {
		return nil, fmt.Errorf("failed to save screenshot to %s: %w", outputPath, err)
	}

	// Get file info
	fileInfo, err := os.Stat(outputPath)
	if err != nil {
		return nil, fmt.Errorf("failed to get file info: %w", err)
	}

	// Create metadata
	metadata := &ScreenshotMetadata{
		Timestamp: time.Now().Format(time.RFC3339),
		URL:       pageInfo.URL,
		Title:     pageInfo.Title,
		FullPage:  fullPage,
		FilePath:  outputPath,
		FileSize:  fileInfo.Size(),
	}

	metadata.ViewportSize.Width = viewportWidth
	metadata.ViewportSize.Height = viewportHeight

	// Get actual image dimensions (approximate based on viewport or full page)
	if fullPage {
		// For full page, we'd need to calculate the full document size
		// For now, use viewport size as approximation
		metadata.Resolution.Width = viewportWidth
		metadata.Resolution.Height = viewportHeight
	} else {
		metadata.Resolution.Width = viewportWidth
		metadata.Resolution.Height = viewportHeight
	}

	d.debugLog("Successfully captured enhanced screenshot for tab: %s", tabID)
	return metadata, nil
}

// FileOperation represents a single file operation
type FileOperation struct {
	LocalPath     string `json:"local_path"`
	ContainerPath string `json:"container_path"`
	Operation     string `json:"operation"` // "upload" or "download"
}

// BulkFileResult represents the result of bulk file operations
type BulkFileResult struct {
	Successful []FileOperationResult `json:"successful"`
	Failed     []FileOperationError  `json:"failed"`
	Summary    struct {
		Total      int `json:"total"`
		Successful int `json:"successful"`
		Failed     int `json:"failed"`
	} `json:"summary"`
}

// FileOperationResult represents a successful file operation
type FileOperationResult struct {
	LocalPath     string `json:"local_path"`
	ContainerPath string `json:"container_path"`
	Operation     string `json:"operation"`
	Size          int64  `json:"size"`
}

// FileOperationError represents a failed file operation
type FileOperationError struct {
	LocalPath     string `json:"local_path"`
	ContainerPath string `json:"container_path"`
	Operation     string `json:"operation"`
	Error         string `json:"error"`
}

// bulkFiles performs bulk file operations (upload/download)
func (d *Daemon) bulkFiles(operationType, filesJSON string, timeout int) (*BulkFileResult, error) {
	d.debugLog("Performing bulk file operations: %s", operationType)

	// Parse the files JSON
	var operations []FileOperation
	err := json.Unmarshal([]byte(filesJSON), &operations)
	if err != nil {
		return nil, fmt.Errorf("failed to parse files JSON: %w", err)
	}

	result := &BulkFileResult{
		Successful: make([]FileOperationResult, 0),
		Failed:     make([]FileOperationError, 0),
	}

	// Set up timeout context
	ctx := context.Background()
	if timeout > 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
		defer cancel()
	}

	// Process each file operation
	for _, op := range operations {
		select {
		case <-ctx.Done():
			// Timeout reached, add remaining operations as failed
			for i := len(result.Successful) + len(result.Failed); i < len(operations); i++ {
				result.Failed = append(result.Failed, FileOperationError{
					LocalPath:     operations[i].LocalPath,
					ContainerPath: operations[i].ContainerPath,
					Operation:     operations[i].Operation,
					Error:         "operation timed out",
				})
			}
			break
		default:
			// Perform the operation
			if op.Operation == "upload" || (op.Operation == "" && operationType == "upload") {
				err := d.performFileUpload(op.LocalPath, op.ContainerPath)
				if err != nil {
					result.Failed = append(result.Failed, FileOperationError{
						LocalPath:     op.LocalPath,
						ContainerPath: op.ContainerPath,
						Operation:     "upload",
						Error:         err.Error(),
					})
				} else {
					// Get file size
					fileInfo, _ := os.Stat(op.ContainerPath)
					size := int64(0)
					if fileInfo != nil {
						size = fileInfo.Size()
					}
					result.Successful = append(result.Successful, FileOperationResult{
						LocalPath:     op.LocalPath,
						ContainerPath: op.ContainerPath,
						Operation:     "upload",
						Size:          size,
					})
				}
			} else if op.Operation == "download" || (op.Operation == "" && operationType == "download") {
				err := d.performFileDownload(op.ContainerPath, op.LocalPath)
				if err != nil {
					result.Failed = append(result.Failed, FileOperationError{
						LocalPath:     op.LocalPath,
						ContainerPath: op.ContainerPath,
						Operation:     "download",
						Error:         err.Error(),
					})
				} else {
					// Get file size
					fileInfo, _ := os.Stat(op.LocalPath)
					size := int64(0)
					if fileInfo != nil {
						size = fileInfo.Size()
					}
					result.Successful = append(result.Successful, FileOperationResult{
						LocalPath:     op.LocalPath,
						ContainerPath: op.ContainerPath,
						Operation:     "download",
						Size:          size,
					})
				}
			} else {
				result.Failed = append(result.Failed, FileOperationError{
					LocalPath:     op.LocalPath,
					ContainerPath: op.ContainerPath,
					Operation:     op.Operation,
					Error:         "unknown operation type",
				})
			}
		}
	}

	// Update summary
	result.Summary.Total = len(operations)
	result.Summary.Successful = len(result.Successful)
	result.Summary.Failed = len(result.Failed)

	d.debugLog("Bulk file operations completed: %d successful, %d failed", result.Summary.Successful, result.Summary.Failed)
	return result, nil
}

// performFileUpload handles a single file upload operation
func (d *Daemon) performFileUpload(localPath, containerPath string) error {
	// Open the source file
	sourceFile, err := os.Open(localPath)
	if err != nil {
		return fmt.Errorf("failed to open source file: %w", err)
	}
	defer sourceFile.Close()

	// Create the destination file
	destFile, err := os.Create(containerPath)
	if err != nil {
		return fmt.Errorf("failed to create destination file: %w", err)
	}
	defer destFile.Close()

	// Copy the file
	_, err = io.Copy(destFile, sourceFile)
	if err != nil {
		return fmt.Errorf("failed to copy file: %w", err)
	}

	return nil
}

// performFileDownload handles a single file download operation
func (d *Daemon) performFileDownload(containerPath, localPath string) error {
	// Open the source file
	sourceFile, err := os.Open(containerPath)
	if err != nil {
		return fmt.Errorf("failed to open source file: %w", err)
	}
	defer sourceFile.Close()

	// Create the destination file
	destFile, err := os.Create(localPath)
	if err != nil {
		return fmt.Errorf("failed to create destination file: %w", err)
	}
	defer destFile.Close()

	// Copy the file
	_, err = io.Copy(destFile, sourceFile)
	if err != nil {
		return fmt.Errorf("failed to copy file: %w", err)
	}

	return nil
}

// FileManagementResult represents the result of file management operations
type FileManagementResult struct {
	Operation string                 `json:"operation"`
	Files     []FileInfo             `json:"files,omitempty"`
	Cleaned   []string               `json:"cleaned,omitempty"`
	Summary   map[string]interface{} `json:"summary"`
}

// FileInfo represents information about a file
type FileInfo struct {
	Path        string    `json:"path"`
	Size        int64     `json:"size"`
	ModTime     time.Time `json:"mod_time"`
	IsDir       bool      `json:"is_dir"`
	Permissions string    `json:"permissions"`
}

// manageFiles performs file management operations
func (d *Daemon) manageFiles(operation, pattern, maxAge string) (*FileManagementResult, error) {
	d.debugLog("Performing file management operation: %s", operation)

	result := &FileManagementResult{
		Operation: operation,
		Summary:   make(map[string]interface{}),
	}

	switch operation {
	case "cleanup":
		return d.cleanupFiles(pattern, maxAge, result)
	case "list":
		return d.listFiles(pattern, result)
	case "info":
		return d.getFileInfo(pattern, result)
	default:
		return nil, fmt.Errorf("unknown file management operation: %s", operation)
	}
}

// cleanupFiles removes files matching pattern and age criteria
func (d *Daemon) cleanupFiles(pattern, maxAge string, result *FileManagementResult) (*FileManagementResult, error) {
	// Parse max age (default to 24 hours if not specified)
	maxAgeHours := 24
	if maxAge != "" {
		if parsed, err := strconv.Atoi(maxAge); err == nil && parsed > 0 {
			maxAgeHours = parsed
		}
	}

	cutoffTime := time.Now().Add(-time.Duration(maxAgeHours) * time.Hour)

	// Default pattern if not specified
	if pattern == "" {
		pattern = "/tmp/cremote-*"
	}

	// Find files matching pattern
	matches, err := filepath.Glob(pattern)
	if err != nil {
		return nil, fmt.Errorf("failed to find files matching pattern: %w", err)
	}

	var cleaned []string
	var totalSize int64

	for _, filePath := range matches {
		fileInfo, err := os.Stat(filePath)
		if err != nil {
			continue // Skip files we can't stat
		}

		// Check if file is older than cutoff time
		if fileInfo.ModTime().Before(cutoffTime) {
			totalSize += fileInfo.Size()
			err = os.Remove(filePath)
			if err != nil {
				d.debugLog("Failed to remove file %s: %v", filePath, err)
			} else {
				cleaned = append(cleaned, filePath)
			}
		}
	}

	result.Cleaned = cleaned
	result.Summary["files_cleaned"] = len(cleaned)
	result.Summary["total_size_freed"] = totalSize
	result.Summary["cutoff_time"] = cutoffTime.Format(time.RFC3339)

	d.debugLog("Cleanup completed: %d files removed, %d bytes freed", len(cleaned), totalSize)
	return result, nil
}

// listFiles lists files matching pattern
func (d *Daemon) listFiles(pattern string, result *FileManagementResult) (*FileManagementResult, error) {
	// Default pattern if not specified
	if pattern == "" {
		pattern = "/tmp/*"
	}

	// Find files matching pattern
	matches, err := filepath.Glob(pattern)
	if err != nil {
		return nil, fmt.Errorf("failed to find files matching pattern: %w", err)
	}

	var files []FileInfo
	var totalSize int64

	for _, filePath := range matches {
		fileInfo, err := os.Stat(filePath)
		if err != nil {
			continue // Skip files we can't stat
		}

		files = append(files, FileInfo{
			Path:        filePath,
			Size:        fileInfo.Size(),
			ModTime:     fileInfo.ModTime(),
			IsDir:       fileInfo.IsDir(),
			Permissions: fileInfo.Mode().String(),
		})

		if !fileInfo.IsDir() {
			totalSize += fileInfo.Size()
		}
	}

	result.Files = files
	result.Summary["total_files"] = len(files)
	result.Summary["total_size"] = totalSize

	d.debugLog("Listed %d files matching pattern: %s", len(files), pattern)
	return result, nil
}

// getFileInfo gets detailed information about a specific file
func (d *Daemon) getFileInfo(filePath string, result *FileManagementResult) (*FileManagementResult, error) {
	if filePath == "" {
		return nil, fmt.Errorf("file path is required for info operation")
	}

	fileInfo, err := os.Stat(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to get file info: %w", err)
	}

	files := []FileInfo{{
		Path:        filePath,
		Size:        fileInfo.Size(),
		ModTime:     fileInfo.ModTime(),
		IsDir:       fileInfo.IsDir(),
		Permissions: fileInfo.Mode().String(),
	}}

	result.Files = files
	result.Summary["exists"] = true
	result.Summary["size"] = fileInfo.Size()
	result.Summary["is_directory"] = fileInfo.IsDir()
	result.Summary["last_modified"] = fileInfo.ModTime().Format(time.RFC3339)

	d.debugLog("Retrieved info for file: %s", filePath)
	return result, nil
}
