package onexbet

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

	webspider "gordenko.dev/dima/spider"
)

// ListLiveMatchesBySport - букмекер возвращает много мусора, типа киберспорта, поэтому метод
// champFilter фильтрует разный мусор
func ListLiveMatchesBySport(sportID OnexbetSport) (list []LiveMatch, err error) {
	url := fmt.Sprintf(liveSportURLPattern, sportID)

	spider, err := webspider.NewSpider(nil)
	if err != nil {
		panic(err)
	}

	buf, err := spider.Get(url, nil)
	if err != nil {
		return
	}

	var rawList liveList

	err = json.Unmarshal(buf, &rawList)
	if err != nil {
		return
	}

	var champFilter func(string) bool

	switch sportID {
	case Football:
		champFilter = FootballChampFilter

	case Handball:
		champFilter = HandballChampFilter

	case Tennis:
		champFilter = TennisChampFilter
	}

	for _, m := range rawList.Value {
		m.ChampName = strings.TrimSpace(m.ChampName)

		if champFilter != nil {
			if !champFilter(m.ChampName) {
				continue
			}
		}

		scoreByPeriods := make(map[int]Score)

		stat := m.Stat

		for _, p := range stat.ScoreByPeriods {
			scoreByPeriods[p.Period] = Score{
				Home: p.Score.HomeScore,
				Away: p.Score.AwayScore,
			}
		}

		list = append(list, LiveMatch{
			MatchID:       fmt.Sprintf("%d", m.MatchID),
			Home:          m.Home,
			Away:          m.Away,
			StartTime:     m.StartTime,
			ChampName:     m.ChampName,
			SportName:     m.SportName,
			StatsMatchID:  m.StatsMatchID,
			CurrentPeriod: stat.CurrentPeriod,
			Score: Score{
				Home: stat.Score.HomeScore,
				Away: stat.Score.AwayScore,
			},
			ScoreByPeriods: scoreByPeriods,
		})
	}

	return
}

func LoadTeamLiveMatchData(matchID string) (_ TeamLiveMatchData, isMatchFinished bool, err error) {
	url := fmt.Sprintf(liveMatchURLPattern, matchID)

	spider, err := webspider.NewSpider(nil)
	if err != nil {
		panic(err)
	}

	buf, err := spider.Get(url, nil)
	if err != nil {
		return
	}

	//fmt.Printf("buf: %s\n\n", buf)

	var env teamLiveMatchDataEnvelope

	err = json.Unmarshal(buf, &env)
	if err != nil {
		err = fmt.Errorf("json.Unmarshal liveMatchDataEnvelope: %s", err)
		return
	}

	if !env.Success {
		isMatchFinished = true
		return
	}

	data := TeamLiveMatchData{
		MatchID: matchID,
	}

	// FULL TIME
	for _, market := range env.Value.GE {
		switch market.MarketType {
		case teamMarketWinner3Way:
			if len(market.OffersList) != 3 {
				// ВАЖНО!
				// Встречается такая херня, что принимают ставки только на 1 или 2 исхода.
				fmt.Printf("1x2 market must have 3 arrays of offers (1, x, 2), not %d", len(market.OffersList))
				break
			}

			// [
			//   {
			//     "C": 1.48,
			//     "G": 1,
			//     "T": 1 // 1
			//   }
			// ],
			// [
			//   {
			//     "C": 6.11,
			//     "G": 1,
			//     "T": 2 // DRAW
			//   }
			// ],
			// [
			//   {
			//     "C": 4.38,
			//     "G": 1,
			//     "T": 3 // 2
			//   }
			// ]

			winner := &Winner3Way{}

			homeList := market.OffersList[0]
			if len(homeList) == 1 {
				winner.Home = homeList[0].Price
			}

			drawList := market.OffersList[1]
			if len(drawList) == 1 {
				winner.Draw = drawList[0].Price
			}

			awayList := market.OffersList[2]
			if len(awayList) == 1 {
				winner.Away = awayList[0].Price
			}

			data.Winner = winner

		case teamMarketTotal:
			data.Total, err = getTotal(market)
			if err != nil {
				err = fmt.Errorf("Full Time total football getTotal: %s", err)
				return
			}

		case teamMarketIndividualTotal1:
			data.IndividualTotalHome, err = getTotal(market)
			if err != nil {
				err = fmt.Errorf("Full Time individual total 1 football getTotal: %s", err)
				return
			}

		case teamMarketIndividualTotal2:
			data.IndividualTotalAway, err = getTotal(market)
			if err != nil {
				err = fmt.Errorf("Full Time individual total 2 football getTotal: %s", err)
				return
			}
		}
	}

	// Статистика
	stats := env.Value.SC
	// Текущее время матча в секундах
	data.CurrentTime = stats.CurrentTime
	data.HomeGoals = stats.FullTimeScore.HomeScore
	data.AwayGoals = stats.FullTimeScore.AwayScore

	for _, pair := range stats.Stats {
		switch pair.Key {
		case "Attacks1":
			data.HomeAttacks, _ = strconv.Atoi(pair.Value)

		case "Attacks2":
			data.AwayAttacks, _ = strconv.Atoi(pair.Value)

		case "DanAttacks1":
			data.HomeDangerousAttacks, _ = strconv.Atoi(pair.Value)

		case "DanAttacks2":
			data.AwayDangerousAttacks, _ = strconv.Atoi(pair.Value)

		case "ShotsOn1":
			data.HomeShotsOnTarget, _ = strconv.Atoi(pair.Value)

		case "ShotsOn2":
			data.AwayShotsOnTarget, _ = strconv.Atoi(pair.Value)

		case "ShotsOff1":
			data.HomeShotsOffTarget, _ = strconv.Atoi(pair.Value)

		case "ShotsOff2":
			data.AwayShotsOffTarget, _ = strconv.Atoi(pair.Value)
		}
	}

	// SubMatchID первого и второго тайма
	//type teamSubMatchIDs struct {
	//	H1 string
	//	H2 string
	//}

	var h1MatchID string
	//var h2MatchID string

	//var subMatchIDs teamSubMatchIDs

	if len(env.Value.BIG) > 0 {
		//fmt.Printf("\n\nBIG: %v\n\n", env.Value.BIG)

		// Парсим 1st HALF
		for _, item := range env.Value.BIG {
			period := strings.ToLower(strings.TrimSpace(item.PeriodName))

			switch period {
			case "1 half":
				if item.SubCategory == "" {
					h1MatchID = strconv.Itoa(item.SubMatchID)
				}

				//case "2 half":
				//	if item.SubCategory == "" {
				//		h2MatchID = strconv.Itoa(item.SubMatchID)
				//	}
			}
		}
	} else {
		//fmt.Printf("\n\nSG: %v\n\n", env.Value.SG)

		// Парсим 1st HALF
		for _, item := range env.Value.SG {
			period := strings.ToLower(strings.TrimSpace(item.PeriodName))

			switch period {
			case "1 half":
				if item.SubCategory == "" {
					h1MatchID = strconv.Itoa(item.SubMatchID)
				}

				//case "2 half":
				//	if item.SubCategory == "" {
				//		h2MatchID = strconv.Itoa(item.SubMatchID)
				//	}
			}
		}
	}

	//fmt.Printf("\n\nsubMatchIDs: %v\n\n", subMatchIDs)

	if h1MatchID != "" {
		url = fmt.Sprintf(liveMatchURLPattern, h1MatchID)
		//fmt.Printf("Load sub url: %s", url)

		buf, err = spider.Get(url, nil)
		if err != nil {
			// Не загрузился 1й тайм - ну и хер с ним. Просто логгируем
			fmt.Printf("Load sub: %s", err)
			return
		}

		var env teamLiveMatchDataEnvelope

		err = json.Unmarshal(buf, &env)
		if err != nil {
			err = fmt.Errorf("json.Unmarshal liveMatchDataEnvelope: %s", err)
			return
		}

		if !env.Success {
			return
		}

		var half Half

		//
		for _, market := range env.Value.GE {
			switch market.MarketType {
			case teamMarketTotal:
				//fmt.Printf("h1 total: %v\n\n", market)

				half.Total, err = getTotal(market)
				if err != nil {
					err = fmt.Errorf("1st Half total football getTotal: %s", err)
					return
				}

			case teamMarketIndividualTotal1:
				//fmt.Printf("h1 total 1: %v\n\n", market)

				half.IndividualTotalHome, err = getTotal(market)
				if err != nil {
					err = fmt.Errorf("1st Half individual total 1 football getTotal: %s", err)
					return
				}

			case teamMarketIndividualTotal2:
				//fmt.Printf("h1 total 2: %v\n\n", market)

				half.IndividualTotalAway, err = getTotal(market)
				if err != nil {
					err = fmt.Errorf("1st Half individual total 2 football getTotal: %s", err)
					return
				}
			}
		}

		data.H1 = half
	}

	//fmt.Printf("%s\n\n", buf)

	return data, false, nil
}

/*
type matchPeriod struct {
	// Football, Handball: 1 - half 1, 3 - half 2
	// Tennis: 11 - 1st set, 12 - 2nd set, 13 - 3rd set
	Type   int
	Score1 int
	Score2 int
}

// Можно получить и доп. статистику, атак, ударов, где periodType - это
// 1 - тайм 1, 3 - тайм 2, 100 - весь матч
type matchStats struct {
	Score1 int
	Score2 int
	Status int // 1 - line, 2 - inplay, 3 - end
	//Winner  int // в inplay не 0?
	Periods []matchPeriod
}

const (
	// для гандбола тоже справедливо
	footballH1 = 1
	footballH2 = 3
)

// GetTeamMatchResult - возвращает счет матча, счет по таймам. Подходит для футбола
// и гандбола.
func GetTeamMatchResult(statsMatchID string) (stats TeamMatchResult, err error) {
	url := fmt.Sprintf(matchStatsURLPattern, statsMatchID)

	spider, err := webspider.NewSpider(nil)
	if err != nil {
		panic(err)
	}

	buf, err := spider.Get(url, nil)
	if err != nil {
		return
	}

	fmt.Printf("Response: %s\n", buf)

	var raw matchStats

	err = json.Unmarshal(buf, &raw)
	if err != nil {
		return
	}

	//stats.Winner = raw.Winner
	stats.Status = raw.Status
	stats.HomeGoals = raw.Score1
	stats.AwayGoals = raw.Score2
	// tennis
	stats.Score.Home = raw.Score1
	stats.Score.Away = raw.Score2
	stats.ScoreByPeriods = make(map[int]Score)

	for _, period := range raw.Periods {
		switch period.Type {
		case footballH1:
			//  fix - позже удалить H1 и H2
			stats.H1 = &HalfStats{
				HomeGoals: period.Score1,
				AwayGoals: period.Score2,
			}
			stats.ScoreByPeriods[1] = Score{
				Home: period.Score1,
				Away: period.Score2,
			}

		case footballH2:
			//  fix - позже удалить H1 и H2
			stats.H2 = &HalfStats{
				HomeGoals: period.Score1,
				AwayGoals: period.Score2,
			}
			stats.ScoreByPeriods[2] = Score{
				Home: period.Score1,
				Away: period.Score2,
			}
		}
	}
	return
}
*/

func GetTeamMatchResult(statsMatchID string) (result TeamMatchResult, err error) {
	url := fmt.Sprintf(matchStatsURLPattern, statsMatchID)

	spider, err := webspider.NewSpider(nil)
	if err != nil {
		panic(err)
	}

	buf, err := spider.Get(url, nil)
	if err != nil {
		return
	}

	//fmt.Printf("%s\n", buf)

	var tmp matchResult

	err = json.Unmarshal(buf, &tmp)
	if err != nil {
		return
	}

	result.Status = tmp.Status
	result.ScoreByPeriods = make(map[int]PeriodScore)

	for _, p := range tmp.Periods {
		periodNumber := periodCode2PeriodNumberMapping[p.Code]
		if periodNumber == 0 {
			continue
		}

		result.ScoreByPeriods[periodNumber] = PeriodScore{
			HomePoints: p.HomePoints,
			AwayPoints: p.AwayPoints,
		}

		result.HomePoints += p.HomePoints
		result.AwayPoints += p.AwayPoints
	}

	return
}
