package browser

import (
	"fmt"
)

// CdpFrame representa un frame/iframe del arbol de navegacion.
type CdpFrame struct {
	ID       string `json:"id"`
	ParentID string `json:"parentId"`
	URL      string `json:"url"`
	Name     string `json:"name"`
}

// CdpListFrames lista todos los frames de la pagina actual (frame raiz + iframes anidados)
// usando Page.getFrameTree. Retorna el arbol aplanado con cada frame y su parentId.
func CdpListFrames(c *CDPConn) ([]CdpFrame, error) {
	if c == nil {
		return nil, fmt.Errorf("cdp list frames: conexion nula")
	}

	// Page.enable es idempotente; necesario para que Page.getFrameTree funcione
	if _, err := c.sendCDP("Page.enable", nil); err != nil {
		return nil, fmt.Errorf("cdp list frames: Page.enable: %w", err)
	}

	result, err := c.sendCDP("Page.getFrameTree", nil)
	if err != nil {
		return nil, fmt.Errorf("cdp list frames: Page.getFrameTree: %w", err)
	}

	frameTree, ok := result["frameTree"].(map[string]any)
	if !ok {
		return nil, fmt.Errorf("cdp list frames: frameTree no encontrado en respuesta")
	}

	var frames []CdpFrame
	frameFlatten(frameTree, "", &frames)
	return frames, nil
}

// frameFlatten recorre recursivamente el arbol de frames CDP y acumula CdpFrame.
// parentID es el ID del nodo padre; el frame raiz lo recibe vacio.
func frameFlatten(node map[string]any, parentID string, acc *[]CdpFrame) {
	frameData, ok := node["frame"].(map[string]any)
	if !ok {
		return
	}

	f := CdpFrame{
		ID:       stringField(frameData, "id"),
		ParentID: parentID,
		URL:      stringField(frameData, "url"),
		Name:     stringField(frameData, "name"),
	}
	*acc = append(*acc, f)

	// Recorrer hijos
	children, _ := node["childFrames"].([]any)
	for _, child := range children {
		childNode, ok := child.(map[string]any)
		if !ok {
			continue
		}
		frameFlatten(childNode, f.ID, acc)
	}
}

// stringField extrae un campo string de un map[string]any de forma segura.
func stringField(m map[string]any, key string) string {
	v, _ := m[key].(string)
	return v
}
