package main

import (
	"errors"
	"net/http"
	"time"

	"github.com/gorilla/mux"
)

type Ranking struct {
	Rank  int
	Teams []Team
}

// getCondorcetResult returns the ranking of teams based on the condorcet method
// https://en.wikipedia.org/wiki/Condorcet_method
func getCondorcetResult() []Ranking {
	type teamPair struct {
		winner   *Team
		loser    *Team
		majority float32
	}
	var allPairs []teamPair
	var ret []Ranking
	for i := 0; i < len(m.jam.Teams); i++ {
		for j := i + 1; j < len(m.jam.Teams); j++ {
			// For each pairing find a winner
			winner, pct, _ := findWinnerBetweenTeams(&m.jam.Teams[i], &m.jam.Teams[j])
			newPair := new(teamPair)
			if winner != nil {
				newPair.winner = winner
				if winner.UUID == m.jam.Teams[i].UUID {
					newPair.loser = &m.jam.Teams[j]
				} else {
					newPair.loser = &m.jam.Teams[i]
				}
				newPair.majority = pct
			} else {
				newPair.winner = &m.jam.Teams[i]
				newPair.loser = &m.jam.Teams[j]
				newPair.majority = 50
			}
			allPairs = append(allPairs, *newPair)
		}
	}
	// initialize map of team wins
	teamWins := make(map[string]int)
	for i := range m.jam.Teams {
		teamWins[m.jam.Teams[i].UUID] = 0
	}
	// Figure out how many wins each team has
	for i := range allPairs {
		if allPairs[i].majority != 50 {
			teamWins[allPairs[i].winner.UUID]++
		}
	}

	// Rank them by wins
	rankedWins := make(map[int][]string)
	for k, v := range teamWins {
		rankedWins[v] = append(rankedWins[v], k)
	}
	currRank := 1
	for len(rankedWins) > 0 {
		topWins := 0
		for k, _ := range rankedWins {
			if k > topWins {
				topWins = k
			}
		}
		nR := new(Ranking)
		nR.Rank = currRank
		for i := range rankedWins[topWins] {
			tm, _ := m.jam.GetTeamById(rankedWins[topWins][i])
			if tm != nil {
				nR.Teams = append(nR.Teams, *tm)
			}
		}
		ret = append(ret, *nR)
		delete(rankedWins, topWins)
		currRank++
	}
	return ret
}

// This is a helper function for calculating results
func uuidIsInRankingSlice(uuid string, sl []Ranking) bool {
	for _, v := range sl {
		for i := range v.Teams {
			if v.Teams[i].UUID == uuid {
				return true
			}
		}
	}
	return false
}

// findWinnerBetweenTeams returns the team that got the most votes
// and the percentage of votes they received
// or an error if a winner couldn't be determined.
func findWinnerBetweenTeams(tm1, tm2 *Team) (*Team, float32, error) {
	// tally gets incremented for a tm1 win, decremented for a tm2 win
	var tm1votes, tm2votes float32
	for _, v := range m.jam.Votes {
		for _, chc := range v.Choices {
			if chc.Team == tm1.UUID {
				tm1votes++
				break
			} else if chc.Team == tm2.UUID {
				tm2votes++
				break
			}
		}
	}
	ttlVotes := tm1votes + tm2votes
	if tm1votes > tm2votes {
		return tm1, 100 * (tm1votes / ttlVotes), nil
	} else if tm1votes < tm2votes {
		return tm2, 100 * (tm2votes / ttlVotes), nil
	}
	return nil, 50, errors.New("Unable to determine a winner")
}

func getInstantRunoffResult() []Team {
	var ret []Team
	return ret
}

func handleAdminVotes(w http.ResponseWriter, req *http.Request, page *pageData) {
	vars := mux.Vars(req)
	page.SubTitle = "Votes"

	type vpdVote struct {
		Timestamp string
		ClientId  string
		Choices   []Team
	}
	type votePageData struct {
		AllVotes []vpdVote
		Results  []Ranking
	}
	vpd := new(votePageData)
	now := time.Now()
	dayThresh := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
	for i := range m.jam.Votes {
		v := new(vpdVote)
		if m.jam.Votes[i].Timestamp.Before(dayThresh) {
			v.Timestamp = m.jam.Votes[i].Timestamp.Format("Jan _2 15:04")
		} else {
			v.Timestamp = m.jam.Votes[i].Timestamp.Format(time.Kitchen)
		}
		v.ClientId = m.jam.Votes[i].ClientId
		for _, choice := range m.jam.Votes[i].Choices {
			for _, fndTm := range m.jam.Teams {
				if fndTm.UUID == choice.Team {
					v.Choices = append(v.Choices, fndTm)
					break
				}
			}
		}
		vpd.AllVotes = append(vpd.AllVotes, *v)
	}
	vpd.Results = getCondorcetResult()
	page.TemplateData = vpd

	switch vars["function"] {
	default:
		page.show("admin-votes.html", w)
	}
}
