package services

import (
	"time"

	"mgit.msbls.de/m/KanzlAI-mGMT/internal/models"
)

// CalculatedDeadline holds a calculated deadline with adjustment info
type CalculatedDeadline struct {
	RuleCode        string `json:"rule_code"`
	RuleID          string `json:"rule_id"`
	Title           string `json:"title"`
	DueDate         string `json:"due_date"`
	OriginalDueDate string `json:"original_due_date"`
	WasAdjusted     bool   `json:"was_adjusted"`
}

// DeadlineCalculator calculates deadlines from rules and event dates
type DeadlineCalculator struct {
	holidays *HolidayService
}

// NewDeadlineCalculator creates a new calculator
func NewDeadlineCalculator(holidays *HolidayService) *DeadlineCalculator {
	return &DeadlineCalculator{holidays: holidays}
}

// CalculateEndDate calculates the end date for a single deadline rule based on an event date.
// Adapted from youpc.org CalculateDeadlineEndDate.
func (c *DeadlineCalculator) CalculateEndDate(eventDate time.Time, rule models.DeadlineRule) (adjusted time.Time, original time.Time, wasAdjusted bool) {
	endDate := eventDate

	timing := "after"
	if rule.Timing != nil {
		timing = *rule.Timing
	}

	durationValue := rule.DurationValue
	durationUnit := rule.DurationUnit

	if timing == "before" {
		switch durationUnit {
		case "days":
			endDate = endDate.AddDate(0, 0, -durationValue)
		case "weeks":
			endDate = endDate.AddDate(0, 0, -durationValue*7)
		case "months":
			endDate = endDate.AddDate(0, -durationValue, 0)
		}
	} else {
		switch durationUnit {
		case "days":
			endDate = endDate.AddDate(0, 0, durationValue)
		case "weeks":
			endDate = endDate.AddDate(0, 0, durationValue*7)
		case "months":
			endDate = endDate.AddDate(0, durationValue, 0)
		}
	}

	original = endDate
	adjusted, _, wasAdjusted = c.holidays.AdjustForNonWorkingDays(endDate)
	return adjusted, original, wasAdjusted
}

// CalculateFromRules calculates deadlines for a set of rules given an event date.
// Returns a list of calculated deadlines with due dates.
func (c *DeadlineCalculator) CalculateFromRules(eventDate time.Time, rules []models.DeadlineRule) []CalculatedDeadline {
	results := make([]CalculatedDeadline, 0, len(rules))

	for _, rule := range rules {
		var adjusted, original time.Time
		var wasAdjusted bool

		if rule.DurationValue > 0 {
			adjusted, original, wasAdjusted = c.CalculateEndDate(eventDate, rule)
		} else {
			adjusted = eventDate
			original = eventDate
		}

		code := ""
		if rule.Code != nil {
			code = *rule.Code
		}

		results = append(results, CalculatedDeadline{
			RuleCode:        code,
			RuleID:          rule.ID.String(),
			Title:           rule.Name,
			DueDate:         adjusted.Format("2006-01-02"),
			OriginalDueDate: original.Format("2006-01-02"),
			WasAdjusted:     wasAdjusted,
		})
	}

	return results
}
