package sla

import (
	"context"
	"log"
	"time"

	"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
)

// DefaultSLACalculator implements the SLACalculator interface
type DefaultSLACalculator struct {
	Timezone      string
	BusinessStart int
	BusinessEnd   int
	Holidays      map[string]bool
}

// NewSLACalculator returns the interface
func NewSLACalculator() domain.SLACalculator {
	return &DefaultSLACalculator{
		Timezone:      "UTC",
		BusinessStart: 9,
		BusinessEnd:   17,
		Holidays:      make(map[string]bool),
	}
}

// CalculateDueDate for the finding based on SLA
func (c *DefaultSLACalculator) CalculateDueDate(severity string) *time.Time {
	var days int
	switch severity {
	case "Critical":
		days = 3
	case "High":
		days = 14
	case "Medium":
		days = 30
	case "Low":
		days = 90
	default:
		days = 30
	}

	loc, err := time.LoadLocation(c.Timezone)
	if err != nil {
		log.Printf("Warning: Invalid timezone '%s', falling back to UTC", c.Timezone)
		loc = time.UTC
	}

	nowLocal := time.Now().In(loc)
	dueDate := c.AddBusinessDays(nowLocal, days)
	return &dueDate
}

// AddBusinessDays for working days not weekends and some holidays
func (c *DefaultSLACalculator) AddBusinessDays(start time.Time, businessDays int) time.Time {
	current := start
	added := 0
	for added < businessDays {
		current = current.AddDate(0, 0, 1)
		weekday := current.Weekday()
		dateStr := current.Format("2006-01-02")
		if weekday != time.Saturday && weekday != time.Sunday && !c.Holidays[dateStr] {
			added++
		}
	}
	return current
}

// CalculateTrueSLAHours based on the time of action for ticket
func (c *DefaultSLACalculator) CalculateTrueSLAHours(ctx context.Context, ticketID int, store domain.Store) (float64, error) {
	appConfig, err := store.GetAppConfig(ctx)
	if err != nil {
		return 0, err
	}

	ticket, err := store.GetTicketByID(ctx, ticketID)
	if err != nil {
		return 0, err
	}

	end := time.Now()
	if ticket.PatchedAt != nil {
		end = *ticket.PatchedAt
	}

	totalActiveBusinessHours := c.calculateBusinessHoursBetween(ticket.CreatedAt, end, appConfig)
	return totalActiveBusinessHours, nil
}

// calculateBusinessHoursBetween calculates strict working hours between two timestamps
func (c *DefaultSLACalculator) calculateBusinessHoursBetween(start, end time.Time, config domain.AppConfig) float64 {
	loc, _ := time.LoadLocation(config.Timezone)
	start = start.In(loc)
	end = end.In(loc)

	if start.After(end) {
		return 0
	}

	var activeHours float64
	current := start

	for current.Before(end) {
		nextHour := current.Add(time.Hour)
		if nextHour.After(end) {
			nextHour = end
		}

		weekday := current.Weekday()
		dateStr := current.Format("2006-01-02")
		hour := current.Hour()

		isWeekend := weekday == time.Saturday || weekday == time.Sunday
		isHoliday := c.Holidays[dateStr]
		isBusinessHour := hour >= config.BusinessStart && hour < config.BusinessEnd

		if !isWeekend && !isHoliday && isBusinessHour {
			activeHours += nextHour.Sub(current).Hours()
		}

		current = nextHour
	}

	return activeHours
}
