package modules

import (
	"fmt"
	"odoo-go/pkg/orm"
)

// ResolveDependencies returns modules in topological order (dependencies first).
// Mirrors: odoo/modules/module_graph.py Graph.add_modules()
//
// Uses Kahn's algorithm for topological sort.
func ResolveDependencies(moduleNames []string) ([]string, error) {
	// Build adjacency list and in-degree map
	inDegree := make(map[string]int)
	dependents := make(map[string][]string) // module → modules that depend on it

	// Initialize all requested modules
	for _, name := range moduleNames {
		if _, exists := inDegree[name]; !exists {
			inDegree[name] = 0
		}
	}

	// Build graph from dependencies
	for _, name := range moduleNames {
		m := Get(name)
		if m == nil {
			return nil, fmt.Errorf("modules: %q not found", name)
		}
		for _, dep := range m.Depends {
			// Ensure dependency is in our set
			if _, exists := inDegree[dep]; !exists {
				inDegree[dep] = 0
			}
			inDegree[name]++
			dependents[dep] = append(dependents[dep], name)
		}
	}

	// Kahn's algorithm
	var queue []string
	for name, degree := range inDegree {
		if degree == 0 {
			queue = append(queue, name)
		}
	}

	var sorted []string
	for len(queue) > 0 {
		// Pop first element
		current := queue[0]
		queue = queue[1:]
		sorted = append(sorted, current)

		// Reduce in-degree for dependents
		for _, dep := range dependents[current] {
			inDegree[dep]--
			if inDegree[dep] == 0 {
				queue = append(queue, dep)
			}
		}
	}

	// Check for circular dependencies
	if len(sorted) != len(inDegree) {
		var circular []string
		for name, degree := range inDegree {
			if degree > 0 {
				circular = append(circular, name)
			}
		}
		return nil, fmt.Errorf("modules: circular dependency detected among: %v", circular)
	}

	return sorted, nil
}

// LoadModules initializes all modules in dependency order.
// Mirrors: odoo/modules/loading.py load_modules()
func LoadModules(moduleNames []string) error {
	sorted, err := ResolveDependencies(moduleNames)
	if err != nil {
		return err
	}

	// Phase 1: Call Init() for each module (registers models and fields)
	for _, name := range sorted {
		m := Get(name)
		if m == nil {
			continue
		}
		if m.Init != nil {
			m.Init()
		}
	}

	// Phase 2: Call PostInit() after all models are registered
	for _, name := range sorted {
		m := Get(name)
		if m == nil {
			continue
		}
		if m.PostInit != nil {
			m.PostInit()
		}
	}

	// Phase 3: Generate Related fields for _inherits delegation
	orm.SetupAllInherits()

	// Phase 4: Build computed field dependency maps
	orm.SetupAllComputes()

	return nil
}
