package main

import (
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"fn-registry/functions/browser"
)

// runBrowserOp executes a browser CDP operation by connecting to Chrome's
// remote debugging endpoint, dispatching the op, and closing the connection.
//
// Supported ops (passed via args.op):
//   - list_tabs                        → []CdpTab
//   - navigate(url)                    → ok
//   - click_text(text, tag?, exact?)   → ok
//   - evaluate(expression)             → string
//   - screenshot(filename?)            → path saved
//   - type_text(selector, text)        → ok
//   - get_html(selector?)              → html
//
// host + port come from manifest. Defaults: 127.0.0.1:9223.
func runBrowserOp(cap *Capability, op string, args map[string]any) (any, int, error) {
	host := cap.ChromeCDPHost
	if host == "" {
		host = "127.0.0.1"
	}
	port := cap.ChromeCDPPort
	if port == 0 {
		port = 9223
	}

	// list_tabs uses HTTP only — no websocket.
	if op == "list_tabs" {
		tabs, err := browser.CdpListTabs(host, port)
		if err != nil {
			return nil, -1, err
		}
		return map[string]any{"tabs": tabs}, 0, nil
	}

	// launch_chrome bootstraps Chrome with --remote-debugging-port.
	// Idempotent: if the port is already serving CDP, ChromeLaunch's
	// waitCDPReady connects to the existing process and returns success.
	if op == "launch_chrome" {
		opts := browser.ChromeLaunchOpts{Port: port}
		if hl, ok := args["headless"].(bool); ok {
			opts.Headless = hl
		}
		if udd, ok := args["user_data_dir"].(string); ok && udd != "" {
			opts.UserDataDir = udd
		}
		if cp, ok := args["chrome_path"].(string); ok && cp != "" {
			opts.ChromePath = cp
		}
		pid, err := browser.ChromeLaunch(opts)
		if err != nil {
			return nil, -1, err
		}
		return map[string]any{"pid": pid, "port": port}, 0, nil
	}

	// Operations that need a websocket connection.
	conn, err := browser.CdpConnectHost(host, port)
	if err != nil {
		return nil, -1, fmt.Errorf("cdp connect %s:%d: %w", host, port, err)
	}
	defer browser.CdpClose(conn, 0)

	switch op {
	case "navigate":
		url, _ := args["url"].(string)
		if url == "" {
			return nil, -1, fmt.Errorf("navigate: url required")
		}
		if err := browser.CdpNavigate(conn, url); err != nil {
			return nil, -1, err
		}
		return map[string]any{"ok": true, "url": url}, 0, nil

	case "click_text":
		text, _ := args["text"].(string)
		if text == "" {
			return nil, -1, fmt.Errorf("click_text: text required")
		}
		tag, _ := args["tag"].(string)
		exact, _ := args["exact"].(bool)
		opts := browser.FindByTextOpts{Tag: tag, Exact: exact}
		if err := browser.CdpClickText(conn, text, opts); err != nil {
			return nil, -1, err
		}
		return map[string]any{"ok": true, "clicked": text}, 0, nil

	case "evaluate":
		expr, _ := args["expression"].(string)
		if expr == "" {
			return nil, -1, fmt.Errorf("evaluate: expression required")
		}
		val, err := browser.CdpEvaluate(conn, expr)
		if err != nil {
			return nil, -1, err
		}
		return map[string]any{"value": val}, 0, nil

	case "screenshot":
		dir := cap.ScreenshotDir
		if dir == "" {
			dir = filepath.Join("local_files", "screenshots")
		}
		fname, _ := args["filename"].(string)
		if fname == "" {
			fname = fmt.Sprintf("shot_%d.png", time.Now().UnixNano())
		}
		fname = strings.ReplaceAll(fname, "..", "_")
		out := filepath.Join(dir, fname)
		opts := browser.CdpScreenshotOpts{Format: "png"}
		if fp, ok := args["full_page"].(bool); ok {
			opts.FullPage = fp
		}
		if err := browser.CdpScreenshot(conn, out, opts); err != nil {
			return nil, -1, err
		}
		return map[string]any{"path": out}, 0, nil

	case "type_text":
		text, _ := args["text"].(string)
		if text == "" {
			return nil, -1, fmt.Errorf("type_text: text required (will be typed into focused element)")
		}
		if err := browser.CdpTypeText(conn, text); err != nil {
			return nil, -1, err
		}
		return map[string]any{"ok": true}, 0, nil

	case "get_html":
		html, err := browser.CdpGetHTML(conn)
		if err != nil {
			return nil, -1, err
		}
		return map[string]any{"html": html}, 0, nil

	default:
		return nil, -1, fmt.Errorf("browser op %q not supported (list_tabs|navigate|click_text|evaluate|screenshot|type_text|get_html)", op)
	}
}
