package ucca

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

// V2Manifest represents the registry of all v2 obligation files
type V2Manifest struct {
	SchemaVersion  string              `json:"schema_version"`
	Regulations    []V2RegulationEntry `json:"regulations"`
	TOMMappingFile string              `json:"tom_mapping_file"`
	TotalObl       int                 `json:"total_obligations"`
}

// V2RegulationEntry is a single regulation in the manifest
type V2RegulationEntry struct {
	ID      string `json:"id"`
	File    string `json:"file"`
	Version string `json:"version"`
	Count   int    `json:"count"`
}

// V2RegulationFile is the top-level structure of a v2 regulation JSON file
type V2RegulationFile struct {
	Regulation    string              `json:"regulation"`
	Name          string              `json:"name"`
	Description   string              `json:"description"`
	Version       string              `json:"version"`
	EffectiveDate string              `json:"effective_date,omitempty"`
	Obligations   []V2Obligation      `json:"obligations"`
	Controls      []V2Control         `json:"controls,omitempty"`
	IncidentDL    []V2IncidentDL      `json:"incident_deadlines,omitempty"`
}

// V2Obligation is the extended obligation structure
type V2Obligation struct {
	ID                    string            `json:"id"`
	Title                 string            `json:"title"`
	Description           string            `json:"description"`
	AppliesWhen           string            `json:"applies_when"`
	AppliesWhenCondition  *ConditionNode    `json:"applies_when_condition,omitempty"`
	LegalBasis            []V2LegalBasis    `json:"legal_basis"`
	Sources               []V2Source        `json:"sources,omitempty"`
	Category              string            `json:"category"`
	Responsible           string            `json:"responsible"`
	Deadline              *V2Deadline       `json:"deadline,omitempty"`
	Sanctions             *V2Sanctions      `json:"sanctions,omitempty"`
	Evidence              []interface{}     `json:"evidence,omitempty"`
	Priority              string            `json:"priority"`
	TOMControlIDs         []string          `json:"tom_control_ids,omitempty"`
	BreakpilotFeature     string            `json:"breakpilot_feature,omitempty"`
	ValidFrom             string            `json:"valid_from,omitempty"`
	ValidUntil            *string           `json:"valid_until"`
	Version               string            `json:"version,omitempty"`
	ISO27001Mapping       []string          `json:"iso27001_mapping,omitempty"`
	HowToImplement        string            `json:"how_to_implement,omitempty"`
	News                  *V2ObligationNews `json:"news,omitempty"`
}

// V2ObligationNews is news metadata for dashboard display.
// Own text referencing legal basis — never copied from external sources.
type V2ObligationNews struct {
	Headline       string `json:"headline"`
	Summary        string `json:"summary"`
	ActionRequired string `json:"action_required"`
	Affected       string `json:"affected,omitempty"`
	ActionLink     string `json:"action_link,omitempty"`
}

// V2LegalBasis is a legal reference in v2 format
type V2LegalBasis struct {
	Norm              string `json:"norm"`
	Article           string `json:"article"`
	Title             string `json:"title,omitempty"`
	Erwaegungsgrund   string `json:"erwaegungsgrund,omitempty"`
}

// V2Source is an external source reference
type V2Source struct {
	Type string `json:"type"`
	Ref  string `json:"ref"`
}

// V2Deadline is a deadline in v2 format
type V2Deadline struct {
	Type     string `json:"type"`
	Date     string `json:"date,omitempty"`
	Duration string `json:"duration,omitempty"`
	Interval string `json:"interval,omitempty"`
	Event    string `json:"event,omitempty"`
}

// V2Sanctions is sanctions info in v2 format
type V2Sanctions struct {
	MaxFine           string `json:"max_fine,omitempty"`
	PersonalLiability bool   `json:"personal_liability,omitempty"`
	CriminalLiability bool   `json:"criminal_liability,omitempty"`
	Description       string `json:"description,omitempty"`
}

// V2Control is a control in v2 format
type V2Control struct {
	ID              string   `json:"id"`
	Name            string   `json:"name"`
	Description     string   `json:"description,omitempty"`
	Category        string   `json:"category"`
	WhatToDo        string   `json:"what_to_do,omitempty"`
	ISO27001Mapping []string `json:"iso27001_mapping,omitempty"`
	Priority        string   `json:"priority,omitempty"`
}

// V2IncidentDL is an incident deadline in v2 format
type V2IncidentDL struct {
	Phase      string         `json:"phase"`
	Deadline   string         `json:"deadline"`
	Content    string         `json:"content,omitempty"`
	Recipient  string         `json:"recipient,omitempty"`
	LegalBasis []V2LegalBasis `json:"legal_basis,omitempty"`
}

// ConditionNode represents a condition tree node for obligation applicability
type ConditionNode struct {
	AllOf    []ConditionNode `json:"all_of,omitempty"`
	AnyOf   []ConditionNode `json:"any_of,omitempty"`
	Field    string          `json:"field,omitempty"`
	Operator string          `json:"operator,omitempty"`
	Value    interface{}     `json:"value,omitempty"`
}

// V2TOMMapping is the bidirectional mapping file
type V2TOMMapping struct {
	SchemaVersion       string                       `json:"schema_version"`
	ObligationToControl map[string][]string           `json:"obligation_to_control"`
	ControlToObligation map[string][]string           `json:"control_to_obligation"`
}

// getV2BasePath returns the base path for v2 obligation files
func getV2BasePath() string {
	// Try relative to the binary
	candidates := []string{
		"policies/obligations/v2",
		"../policies/obligations/v2",
		"../../policies/obligations/v2",
	}

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

	for _, p := range candidates {
		abs, err := filepath.Abs(p)
		if err != nil {
			continue
		}
		if info, err := os.Stat(abs); err == nil && info.IsDir() {
			return abs
		}
	}

	return "policies/obligations/v2"
}

// LoadV2Manifest loads the v2 manifest file
func LoadV2Manifest() (*V2Manifest, error) {
	basePath := getV2BasePath()
	manifestPath := filepath.Join(basePath, "_manifest.json")

	data, err := os.ReadFile(manifestPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read v2 manifest: %w", err)
	}

	var manifest V2Manifest
	if err := json.Unmarshal(data, &manifest); err != nil {
		return nil, fmt.Errorf("failed to parse v2 manifest: %w", err)
	}

	return &manifest, nil
}

// LoadV2RegulationFile loads a single v2 regulation JSON file
func LoadV2RegulationFile(filename string) (*V2RegulationFile, error) {
	basePath := getV2BasePath()
	filePath := filepath.Join(basePath, filename)

	data, err := os.ReadFile(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to read v2 regulation file %s: %w", filename, err)
	}

	var regFile V2RegulationFile
	if err := json.Unmarshal(data, &regFile); err != nil {
		return nil, fmt.Errorf("failed to parse v2 regulation file %s: %w", filename, err)
	}

	return &regFile, nil
}

// LoadV2TOMMapping loads the bidirectional TOM mapping
func LoadV2TOMMapping() (*V2TOMMapping, error) {
	basePath := getV2BasePath()
	mappingPath := filepath.Join(basePath, "_tom_mapping.json")

	data, err := os.ReadFile(mappingPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read TOM mapping: %w", err)
	}

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

	return &mapping, nil
}

// LoadAllV2Regulations loads all v2 regulation files from the manifest
func LoadAllV2Regulations() (map[string]*V2RegulationFile, error) {
	manifest, err := LoadV2Manifest()
	if err != nil {
		return nil, err
	}

	result := make(map[string]*V2RegulationFile)
	for _, entry := range manifest.Regulations {
		regFile, err := LoadV2RegulationFile(entry.File)
		if err != nil {
			fmt.Printf("Warning: Could not load v2 regulation %s: %v\n", entry.ID, err)
			continue
		}
		result[entry.ID] = regFile
	}

	return result, nil
}
