package ucca

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
)

// TOMControl represents a single TOM control from the control library
type TOMControl struct {
	ID                     string            `json:"id"`
	Title                  string            `json:"title"`
	Description            string            `json:"description"`
	Type                   string            `json:"type"` // ORGANIZATIONAL, TECHNICAL
	ImplementationGuidance string            `json:"implementation_guidance,omitempty"`
	Evidence               []string          `json:"evidence,omitempty"`
	AppliesIf              *TOMAppliesIf     `json:"applies_if,omitempty"`
	RiskTier               string            `json:"risk_tier"` // BASELINE, ENHANCED, ADVANCED
	Mappings               TOMControlMapping `json:"mappings,omitempty"`
	ReviewFrequency        string            `json:"review_frequency,omitempty"`
	Priority               string            `json:"priority"` // CRITICAL, HIGH, MEDIUM, LOW
	Complexity             string            `json:"complexity,omitempty"`
	DomainID               string            `json:"domain_id,omitempty"` // set during loading
}

// TOMAppliesIf defines when a control applies
type TOMAppliesIf struct {
	Field    string      `json:"field"`
	Operator string      `json:"operator"`
	Value    interface{} `json:"value"`
}

// TOMControlMapping maps a control to various standards
type TOMControlMapping struct {
	GDPR    []string `json:"gdpr,omitempty"`
	ISO27001 []string `json:"iso27001,omitempty"`
	BSI     []string `json:"bsi,omitempty"`
	SDM     []string `json:"sdm,omitempty"`
	NIS2    []string `json:"nis2,omitempty"`
}

// TOMControlDomain represents a domain of controls
type TOMControlDomain struct {
	ID        string       `json:"id"`
	Name      string       `json:"name"`
	Objective string       `json:"objective"`
	Controls  []TOMControl `json:"controls"`
}

// TOMControlLibrary is the top-level structure of the control library
type TOMControlLibrary struct {
	Schema  string             `json:"schema"`
	Version string             `json:"version"`
	Domains []TOMControlDomain `json:"domains"`
}

// TOMControlIndex provides fast lookup of controls
type TOMControlIndex struct {
	ByID          map[string]*TOMControl
	ByDomain      map[string][]*TOMControl
	ByGDPRArticle map[string][]*TOMControl
	AllControls   []*TOMControl
}

// LoadTOMControls loads the TOM control library from JSON
func LoadTOMControls() (*TOMControlIndex, error) {
	data, err := readTOMControlsFile()
	if err != nil {
		return nil, err
	}

	var library TOMControlLibrary
	if err := json.Unmarshal(data, &library); err != nil {
		return nil, fmt.Errorf("failed to parse TOM controls: %w", err)
	}

	return buildTOMIndex(&library), nil
}

func readTOMControlsFile() ([]byte, error) {
	// Try multiple candidate paths
	candidates := []string{
		"policies/tom_controls_v1.json",
		"../policies/tom_controls_v1.json",
		"../../policies/tom_controls_v1.json",
	}

	// Also try relative to source file
	_, filename, _, ok := runtime.Caller(0)
	if ok {
		srcDir := filepath.Dir(filename)
		candidates = append(candidates,
			filepath.Join(srcDir, "../../policies/tom_controls_v1.json"),
		)
	}

	for _, p := range candidates {
		abs, err := filepath.Abs(p)
		if err != nil {
			continue
		}
		data, err := os.ReadFile(abs)
		if err == nil {
			return data, nil
		}
	}

	return nil, fmt.Errorf("tom_controls_v1.json not found in any candidate path")
}

func buildTOMIndex(library *TOMControlLibrary) *TOMControlIndex {
	idx := &TOMControlIndex{
		ByID:          make(map[string]*TOMControl),
		ByDomain:      make(map[string][]*TOMControl),
		ByGDPRArticle: make(map[string][]*TOMControl),
	}

	for i := range library.Domains {
		domain := &library.Domains[i]
		for j := range domain.Controls {
			ctrl := &domain.Controls[j]
			ctrl.DomainID = domain.ID

			idx.ByID[ctrl.ID] = ctrl
			idx.ByDomain[domain.ID] = append(idx.ByDomain[domain.ID], ctrl)
			idx.AllControls = append(idx.AllControls, ctrl)

			// Index by GDPR article
			for _, article := range ctrl.Mappings.GDPR {
				idx.ByGDPRArticle[article] = append(idx.ByGDPRArticle[article], ctrl)
			}
		}
	}

	return idx
}

// GetControl returns a control by ID
func (idx *TOMControlIndex) GetControl(id string) (*TOMControl, bool) {
	ctrl, ok := idx.ByID[id]
	return ctrl, ok
}

// GetControlsByDomain returns all controls for a domain
func (idx *TOMControlIndex) GetControlsByDomain(domain string) []*TOMControl {
	return idx.ByDomain[domain]
}

// GetControlsByGDPRArticle returns controls mapped to a GDPR article
func (idx *TOMControlIndex) GetControlsByGDPRArticle(article string) []*TOMControl {
	return idx.ByGDPRArticle[article]
}

// ValidateControlID checks if a control ID exists
func (idx *TOMControlIndex) ValidateControlID(id string) bool {
	_, ok := idx.ByID[id]
	return ok
}
