package main

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	gameTypeUnknown = iota
	gameTypeClassic
)

type Game struct {
	Timestamp time.Time `json:"timestamp"`
	GameType  int       `json:"game_type"`
	Wager     int       `json:"wager"`
	Winner    string    `json:"winner"`
	Loser     string    `json:"loser"`
	HighRoll  int       `json:"high_roll"`
	LowRoll   int       `json:"low_roll"`
	Payout    int       `json:"payout"`
	Players   []string  `json:"players"`
}

var (
	reTimeStamp = regexp.MustCompile(`(\d/\d \d+:\d+:\d+.\d+)`)
	reGameStart = regexp.MustCompile(`WoWGoldGambler: A new game has been started`)
	reWager     = regexp.MustCompile(`Game Mode - ([A-Z]+) - Wager - ([\d,]+)g$`)
	reSignup    = regexp.MustCompile(`([\p{L}']+)-[\p{L}'0-9]+: (1|-1)`)
	reRoll      = regexp.MustCompile(`([\p{L}']+) rolls (\d+) \(1-(\d+)\)$`)
	reEnd       = regexp.MustCompile(`([\p{L}']+) owes ([\p{L}']+) ([\d,]+) gold!`)
)

func parseGames(lines []string) ([]Game, error) {
	games := make([]Game, 0)
	var err error

	i := 0
	for i < len(lines) {
		if reGameStart.MatchString(lines[i]) {
			var game Game
			game, i, err = parse(lines, i)
			if err != nil {
				return nil, err
			}
			games = append(games, game)
		}
		i++
	}

	return games, nil
}

func parse(lines []string, i int) (Game, int, error) {
	var (
		g   Game
		err error
	)

	// Timestamp
	ts := reTimeStamp.FindString(lines[i])
	if ts == "" {
		return g, i, fmt.Errorf("failed to extract timestamp from %s", lines[i])
	}
	g.Timestamp, err = time.Parse("1/2 15:04:05.000", ts)
	if err != nil {
		return g, i, err
	}

	// Wager
	i++
	matches := reWager.FindStringSubmatch(lines[i])
	switch matches[1] {
	case "CLASSIC":
		g.GameType = gameTypeClassic
	default:
		g.GameType = gameTypeUnknown
	}
	g.Wager, err = strconv.Atoi(strings.ReplaceAll(matches[2], ",", ""))
	if err != nil {
		return g, i, err
	}

	// Registration
	for {
		if strings.Contains(lines[i], "Registration has ended") {
			break
		}
		i++
	}

	// Capture Rolls
	rolls := make(map[string]int)
	for {
		if reEnd.MatchString(lines[i]) {
			break
		}

		rollMatches := reRoll.FindStringSubmatch(lines[i])
		if rollMatches == nil {
			i++
			continue
		}

		v, err := strconv.Atoi(rollMatches[3])
		if err != nil {
			return g, i, err
		}
		if v != g.Wager {
			i++
			continue
		}

		// Ignore extra rolls
		if _, ok := rolls[rollMatches[1]]; !ok {
			val, err := strconv.Atoi(rollMatches[2])
			if err != nil {
				return g, i, err
			}
			rolls[rollMatches[1]] = val
		}

		i++
	}

	endMatches := reEnd.FindStringSubmatch(lines[i])
	p := strings.ReplaceAll(endMatches[3], ",", "")
	payout, err := strconv.Atoi(p)
	if err != nil {
		return g, i, err
	}
	g.Payout = payout

	g.Winner = endMatches[2]
	g.HighRoll = rolls[g.Winner]

	g.Loser = endMatches[1]
	g.LowRoll = rolls[g.Loser]

	g.Players = make([]string, 0)
	for pl, _ := range rolls {
		g.Players = append(g.Players, pl)
	}

	return g, i, nil
}