package server

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"
)

// menuRow holds a single row from the ir_ui_menu table joined with ir_model_data.
type menuRow struct {
	ID       int
	Name     string
	ParentID *int   // NULL for top-level menus
	Sequence int
	Action   *string // e.g. "ir.actions.act_window,1"
	WebIcon  *string
	XMLID    string // e.g. "contacts.menu_contacts" from ir_model_data
}

// handleLoadMenus returns the menu tree for the webclient.
// Mirrors: odoo/addons/web/controllers/home.py Home.web_load_menus()
//
// Loads menus from the ir_ui_menu table, builds the parent/child tree,
// and returns the JSON map keyed by string IDs that the webclient expects.
func (s *Server) handleLoadMenus(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Cache-Control", "public, max-age=3600")

	ctx := r.Context()
	menus, err := s.loadWebMenus(ctx)
	if err != nil {
		log.Printf("menus: error loading menus: %v", err)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	json.NewEncoder(w).Encode(menus)
}

// loadWebMenus queries ir_ui_menu and builds the JSON structure the webclient expects.
// Mirrors: odoo/addons/base/models/ir_ui_menu.py IrUiMenu.load_web_menus()
func (s *Server) loadWebMenus(ctx context.Context) (map[string]interface{}, error) {
	// Query all active menus, joined with ir_model_data for the xmlid.
	rows, err := s.pool.Query(ctx, `
		SELECT m.id, m.name, m.parent_id, m.sequence, m.action, m.web_icon,
		       COALESCE(d.module || '.' || d.name, '') AS xmlid
		FROM ir_ui_menu m
		LEFT JOIN ir_model_data d
		       ON d.model = 'ir.ui.menu' AND d.res_id = m.id
		WHERE m.active = true
		ORDER BY m.sequence, m.id`)
	if err != nil {
		return nil, fmt.Errorf("query ir_ui_menu: %w", err)
	}
	defer rows.Close()

	var allMenus []menuRow
	for rows.Next() {
		var mr menuRow
		if err := rows.Scan(&mr.ID, &mr.Name, &mr.ParentID, &mr.Sequence, &mr.Action, &mr.WebIcon, &mr.XMLID); err != nil {
			return nil, fmt.Errorf("scan menu row: %w", err)
		}
		allMenus = append(allMenus, mr)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate menu rows: %w", err)
	}

	// Build children map: parent_id → list of child IDs
	childrenOf := make(map[int][]int)
	for _, m := range allMenus {
		if m.ParentID != nil {
			childrenOf[*m.ParentID] = append(childrenOf[*m.ParentID], m.ID)
		}
	}

	// Find the root app ID for each menu by walking up to the top-level ancestor.
	// Top-level menus (parent_id IS NULL) are their own appID.
	menuByID := make(map[int]*menuRow, len(allMenus))
	for i := range allMenus {
		menuByID[allMenus[i].ID] = &allMenus[i]
	}

	appIDOf := func(id int) int {
		cur := id
		for {
			m, ok := menuByID[cur]
			if !ok || m.ParentID == nil {
				return cur
			}
			cur = *m.ParentID
		}
	}

	// Build the result map
	result := make(map[string]interface{}, len(allMenus)+1)

	// Collect top-level menu IDs (parent_id IS NULL) for the root entry
	var rootChildren []int
	for _, m := range allMenus {
		if m.ParentID == nil {
			rootChildren = append(rootChildren, m.ID)
		}
	}

	// "root" pseudo-entry
	result["root"] = map[string]interface{}{
		"id":                  "root",
		"name":                "root",
		"children":            rootChildren,
		"appID":               false,
		"xmlid":               "",
		"actionID":            false,
		"actionModel":         false,
		"actionPath":          false,
		"webIcon":             nil,
		"webIconData":         nil,
		"webIconDataMimetype": nil,
		"backgroundImage":     nil,
	}

	// Each menu entry
	for _, m := range allMenus {
		children := childrenOf[m.ID]
		if children == nil {
			children = []int{}
		}

		actionID, actionModel := parseMenuAction(m.Action)
		appID := appIDOf(m.ID)

		var webIcon interface{}
		if m.WebIcon != nil && *m.WebIcon != "" {
			webIcon = *m.WebIcon
		}

		result[strconv.Itoa(m.ID)] = map[string]interface{}{
			"id":                  m.ID,
			"name":                m.Name,
			"children":            children,
			"appID":               appID,
			"xmlid":               m.XMLID,
			"actionID":            actionID,
			"actionModel":         actionModel,
			"actionPath":          false,
			"webIcon":             webIcon,
			"webIconData":         nil,
			"webIconDataMimetype": nil,
			"backgroundImage":     nil,
		}
	}

	return result, nil
}

// parseMenuAction parses the Odoo action reference format "ir.actions.act_window,123"
// into an action ID (int or false) and action model (string or false).
// Mirrors: odoo/addons/base/models/ir_ui_menu.py _compute_action()
func parseMenuAction(action *string) (interface{}, interface{}) {
	if action == nil || *action == "" {
		return false, false
	}
	parts := strings.SplitN(*action, ",", 2)
	if len(parts) != 2 {
		return false, false
	}
	model := parts[0]
	id, err := strconv.Atoi(parts[1])
	if err != nil {
		return false, false
	}
	return id, model
}
