package dto

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"
)

type FriendlyDuration time.Duration

func (d *FriendlyDuration) UnmarshalJSON(b []byte) error {
	if len(b) == 0 {
		*d = 0
		return nil
	}

	s := strings.TrimSpace(string(b))
	if s == "null" || s == "" {
		*d = 0
		return nil
	}

	if s[0] == '"' && s[len(s)-1] == '"' {
		str := strings.Trim(s, "\"")
		duration, err := parseDurationString(str)
		if err != nil {
			return err
		}
		*d = FriendlyDuration(duration)
		return nil
	}

	// treat bare numbers as minutes
	var num json.Number
	if err := json.Unmarshal(b, &num); err != nil {
		return err
	}
	f, err := num.Float64()
	if err != nil {
		return err
	}
	*d = FriendlyDuration(time.Duration(f * float64(time.Minute)))
	return nil
}

func (d FriendlyDuration) Duration() time.Duration {
	return time.Duration(d)
}

func parseDurationString(input string) (time.Duration, error) {
	val := strings.TrimSpace(strings.ToLower(input))
	if val == "" {
		return 0, nil
	}

	multiplier := time.Minute
	switch {
	case strings.HasSuffix(val, "min"):
		val = strings.TrimSuffix(val, "min")
	case strings.HasSuffix(val, "h"):
		multiplier = time.Hour
		val = strings.TrimSuffix(val, "h")
	case strings.HasSuffix(val, "s"):
		multiplier = time.Second
		val = strings.TrimSuffix(val, "s")
	default:
		// default minutes, but strip optional trailing m
		val = strings.TrimSuffix(val, "m")
	}

	val = strings.TrimSpace(val)
	if val == "" {
		return 0, fmt.Errorf("invalid duration value: %s", input)
	}

	f, err := strconv.ParseFloat(val, 64)
	if err != nil {
		return 0, fmt.Errorf("invalid duration value %q: %w", input, err)
	}

	return time.Duration(f * float64(multiplier)), nil
}
