package browser

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"time"
)

// ChromeLaunchOpts configura el lanzamiento de Chrome con CDP.
type ChromeLaunchOpts struct {
	// Port es el puerto de remote debugging. Por defecto 9222.
	Port int
	// UserDataDir es el directorio de perfil de Chrome. Por defecto /tmp/chrome-cdp-profile.
	UserDataDir string
	// Headless activa el modo headless (--headless=new). Por defecto false.
	Headless bool
	// ChromePath es la ruta al ejecutable de Chrome. Si esta vacio, se busca automaticamente.
	ChromePath string
	// ExtraArgs permite pasar flags adicionales a Chrome.
	ExtraArgs []string
}

// chromePaths lista los ejecutables de Chrome conocidos en WSL2/Linux.
var chromePaths = []string{
	"chrome.exe",
	"google-chrome",
	"chromium-browser",
	"chromium",
	"/mnt/c/Program Files/Google/Chrome/Application/chrome.exe",
	"/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
	"/mnt/c/Users/Public/Desktop/chrome.exe",
}

// findChrome localiza el ejecutable de Chrome en el sistema.
func findChrome() (string, error) {
	for _, p := range chromePaths {
		if path, err := exec.LookPath(p); err == nil {
			return path, nil
		}
		if _, err := os.Stat(p); err == nil {
			return p, nil
		}
	}
	return "", fmt.Errorf("chrome: ejecutable no encontrado en PATH ni en rutas conocidas de Windows")
}

// waitCDPReady espera hasta que el puerto CDP responda conexiones TCP.
// host puede estar vacio (usa "localhost").
func waitCDPReady(host string, port int, timeout time.Duration) error {
	if host == "" {
		host = "localhost"
	}
	deadline := time.Now().Add(timeout)
	addr := fmt.Sprintf("%s:%d", host, port)
	for time.Now().Before(deadline) {
		conn, err := net.DialTimeout("tcp", addr, 200*time.Millisecond)
		if err == nil {
			conn.Close()
			return nil
		}
		time.Sleep(200 * time.Millisecond)
	}
	return fmt.Errorf("chrome: puerto CDP %s:%d no disponible despues de %s", host, port, timeout)
}

// ChromeLaunch lanza Google Chrome con remote debugging habilitado en el puerto indicado.
// Retorna el PID del proceso Chrome. Espera hasta 15s a que el puerto CDP este listo.
// Busca chrome.exe en PATH (WSL2) o en rutas conocidas de Windows.
func ChromeLaunch(opts ChromeLaunchOpts) (int, error) {
	if opts.Port == 0 {
		opts.Port = 9222
	}
	if opts.UserDataDir == "" {
		opts.UserDataDir = "/tmp/chrome-cdp-profile"
	}

	chromePath := opts.ChromePath
	if chromePath == "" {
		var err error
		chromePath, err = findChrome()
		if err != nil {
			return 0, err
		}
	}

	args := []string{
		fmt.Sprintf("--remote-debugging-port=%d", opts.Port),
		fmt.Sprintf("--user-data-dir=%s", opts.UserDataDir),
		"--no-first-run",
		"--no-default-browser-check",
		"--disable-background-networking",
		"--disable-client-side-phishing-detection",
		"--disable-default-apps",
		"--disable-extensions",
		"--disable-hang-monitor",
		"--disable-popup-blocking",
		"--disable-prompt-on-repost",
		"--disable-sync",
		"--disable-translate",
		"--metrics-recording-only",
		"--safebrowsing-disable-auto-update",
	}

	if opts.Headless {
		args = append(args, "--headless=new", "--disable-gpu")
	}

	args = append(args, opts.ExtraArgs...)

	cmd := exec.Command(chromePath, args...)
	// Chrome necesita que no haya stderr/stdout bloqueados
	cmd.Stdout = nil
	cmd.Stderr = nil

	if err := cmd.Start(); err != nil {
		return 0, fmt.Errorf("chrome: arrancar proceso: %w", err)
	}

	pid := cmd.Process.Pid

	// Esperar a que el puerto CDP este listo
	// Si Chrome escucha en 0.0.0.0 (ej: WSL2 -> Windows), el caller se encarga del wait
	skipWait := false
	for _, a := range opts.ExtraArgs {
		if a == "--remote-debugging-address=0.0.0.0" {
			skipWait = true
			break
		}
	}
	if !skipWait {
		if err := waitCDPReady("localhost", opts.Port, 15*time.Second); err != nil {
			cmd.Process.Kill()
			return 0, err
		}
	}

	return pid, nil
}
