package trello

import (
	"sort"
	"time"

	"github.com/pkg/errors"
)

// ListDuration represents the time a Card has been or was in list.
type ListDuration struct {
	ListID       string
	ListName     string
	Duration     time.Duration
	FirstEntered time.Time
	TimesInList  int
}

// AddDuration takes a duration and adds it to the ListDuration's Duration.
// Also increments TimesInList.
func (l *ListDuration) AddDuration(d time.Duration) {
	l.Duration = l.Duration + d
	l.TimesInList++
}

// GetListDurations analyses a Card's actions to figure out how long it was in each List.
// It returns a slice of the ListDurations, one Duration per list, or an error.
func (c *Card) GetListDurations() (durations []*ListDuration, err error) {

	var actions ActionCollection
	if len(c.Actions) == 0 {
		// Get all actions which affected the Card's List
		c.client.log("[trello] GetListDurations() called on card '%s' without any Card.Actions. Fetching fresh.", c.ID)
		actions, err = c.GetListChangeActions()
		if err != nil {
			err = errors.Wrap(err, "GetListChangeActions() call failed.")
			return
		}
	} else {
		actions = c.Actions.FilterToListChangeActions()
	}

	return actions.GetListDurations()
}

// GetListDurations returns a slice of ListDurations based on the receiver Actions.
func (actions ActionCollection) GetListDurations() (durations []*ListDuration, err error) {
	sort.Sort(actions)

	var prevTime time.Time
	var prevList *List

	durs := make(map[string]*ListDuration)
	for _, action := range actions {
		if action.DidChangeListForCard() {
			if prevList != nil {
				duration := action.Date.Sub(prevTime)
				_, durExists := durs[prevList.ID]
				if !durExists {
					durs[prevList.ID] = &ListDuration{ListID: prevList.ID, ListName: prevList.Name, Duration: duration, TimesInList: 1, FirstEntered: prevTime}
				} else {
					durs[prevList.ID].AddDuration(duration)
				}
			}
			prevList = ListAfterAction(action)
			prevTime = action.Date
		}
	}

	if prevList != nil {
		duration := time.Since(prevTime)
		_, durExists := durs[prevList.ID]
		if !durExists {
			durs[prevList.ID] = &ListDuration{ListID: prevList.ID, ListName: prevList.Name, Duration: duration, TimesInList: 1, FirstEntered: prevTime}
		} else {
			durs[prevList.ID].AddDuration(duration)
		}
	}

	durations = make([]*ListDuration, 0, len(durs))
	for _, ld := range durs {
		durations = append(durations, ld)
	}
	sort.Sort(ByFirstEntered(durations))

	return durations, nil
}
