package ucca

import (
	"fmt"
	"sort"
	"strings"
	"time"
)

// RegulatoryNewsItem is a single news item for dashboard display.
type RegulatoryNewsItem struct {
	ID             string `json:"id"`
	Headline       string `json:"headline"`
	Summary        string `json:"summary"`
	LegalReference string `json:"legal_reference"`
	Deadline       string `json:"deadline"`
	DaysRemaining  int    `json:"days_remaining"`
	Urgency        string `json:"urgency"` // critical, high, medium, low
	Affected       string `json:"affected"`
	ActionRequired string `json:"action_required"`
	ActionLink     string `json:"action_link"`
	Regulation     string `json:"regulation"`
	Sanctions      string `json:"sanctions,omitempty"`
}

// RegulatoryNewsFilter controls which news items are returned.
type RegulatoryNewsFilter struct {
	BusinessModel string `json:"business_model,omitempty"`
	HorizonDays   int    `json:"horizon_days,omitempty"` // default 365
	Limit         int    `json:"limit,omitempty"`         // default 5
}

// GetRegulatoryNews scans all v2 obligations for upcoming deadlines
// and returns formatted news items sorted by urgency.
func GetRegulatoryNews(regulations map[string]*V2RegulationFile, filter RegulatoryNewsFilter) []RegulatoryNewsItem {
	return GetRegulatoryNewsAt(regulations, filter, time.Now().UTC())
}

// GetRegulatoryNewsAt is GetRegulatoryNews with an injectable reference time so the
// upcoming-deadline window is deterministic in tests (no time-bomb once a deadline passes).
func GetRegulatoryNewsAt(regulations map[string]*V2RegulationFile, filter RegulatoryNewsFilter, now time.Time) []RegulatoryNewsItem {
	if filter.HorizonDays <= 0 {
		filter.HorizonDays = 365
	}
	if filter.Limit <= 0 {
		filter.Limit = 5
	}

	today := now.UTC().Truncate(24 * time.Hour)
	horizon := today.AddDate(0, 0, filter.HorizonDays)
	var items []RegulatoryNewsItem

	for _, reg := range regulations {
		for _, obl := range reg.Obligations {
			deadline, ok := resolveDeadline(obl)
			if !ok || deadline.Before(today) || deadline.After(horizon) {
				continue
			}

			days := int(deadline.Sub(today).Hours() / 24)
			item := buildNewsItem(obl, reg.Regulation, deadline, days)
			items = append(items, item)
		}
	}

	sort.Slice(items, func(i, j int) bool {
		return items[i].DaysRemaining < items[j].DaysRemaining
	})

	if len(items) > filter.Limit {
		items = items[:filter.Limit]
	}
	return items
}

func buildNewsItem(obl V2Obligation, regulation string, deadline time.Time, days int) RegulatoryNewsItem {
	item := RegulatoryNewsItem{
		ID:            obl.ID,
		Deadline:      deadline.Format("2006-01-02"),
		DaysRemaining: days,
		Urgency:       computeUrgency(days),
		Regulation:    regulation,
	}

	// Use hand-crafted news if available
	if obl.News != nil {
		item.Headline = obl.News.Headline
		item.Summary = obl.News.Summary
		item.ActionRequired = obl.News.ActionRequired
		item.Affected = obl.News.Affected
		item.ActionLink = obl.News.ActionLink
	} else {
		// Auto-generate from obligation data
		item.Headline = fmt.Sprintf("%s — ab %s", obl.Title, deadline.Format("02.01.2006"))
		item.Summary = obl.Description
		item.ActionRequired = "Pruefen Sie die Anforderungen und ergreifen Sie Massnahmen."
		item.ActionLink = obl.BreakpilotFeature
	}

	item.LegalReference = formatLegalReference(obl.LegalBasis)

	if obl.Sanctions != nil {
		item.Sanctions = obl.Sanctions.MaxFine
	}
	return item
}

func resolveDeadline(obl V2Obligation) (time.Time, bool) {
	// Check explicit deadline.date first
	if obl.Deadline != nil && obl.Deadline.Date != "" {
		t, err := time.Parse("2006-01-02", obl.Deadline.Date)
		if err == nil {
			return t, true
		}
	}
	// Fallback to valid_from
	if obl.ValidFrom != "" {
		t, err := time.Parse("2006-01-02", obl.ValidFrom)
		if err == nil {
			return t, true
		}
	}
	return time.Time{}, false
}

func computeUrgency(daysRemaining int) string {
	switch {
	case daysRemaining <= 30:
		return "critical"
	case daysRemaining <= 90:
		return "high"
	case daysRemaining <= 180:
		return "medium"
	default:
		return "low"
	}
}

func formatLegalReference(bases []V2LegalBasis) string {
	if len(bases) == 0 {
		return ""
	}
	var refs []string
	for _, b := range bases {
		ref := b.Article
		if b.Norm != "" {
			ref = b.Article + " " + b.Norm
		}
		refs = append(refs, ref)
	}
	return strings.Join(refs, ", ")
}
