package daemon

import (
	"fmt"

	"gordenko.dev/dima/flashscore"
	"gordenko.dev/dima/onexbet"
	"gordenko.dev/dima/tipper/model"
)

func FootballHistoryProcessor(match *TeamMatch) {
}

/*
Алгоритм 2
ТБ 0.5 в Матче

До матча:
ТБ 2.5 (в матче) <=1.7
В 75% игр был гол

В Лайве:
Сумма атак обычных и опасных >= 135
6 ударов в сторону ворот OFF TARGET
4 удара в створ ON TARGET

До 70 минуты
*/

type FootballOver05 struct {
	id               int64
	notifyInTelegram bool
	isChampAccepted  func(string) bool
}

func NewFootballOver05(opt StrategyOptions) FootballOver05 {
	if opt.ID == 0 {
		panic("StrategyID not defined")
	}
	s := FootballOver05{}
	s.id = opt.ID
	s.notifyInTelegram = opt.NotifyInTelegram
	s.isChampAccepted = opt.IsChampAccepted
	return s
}

func (s FootballOver05) ID() int64 {
	return s.id
}

func (s FootballOver05) ShortName() string {
	return fmt.Sprintf("#%d FT Over 0.5 M", s.id)
}

func (s FootballOver05) IsNotifyInTelegram() bool {
	return s.notifyInTelegram
}

func (s FootballOver05) GetTelegramTipPattern() string {
	return `Сигнал # %d.
Будет ГОЛ!
Алгоритм %d
Тотал Больше 0.5
Футбол. %s. %s
%s - %s
Коэф. %.3f`
}

func (s FootballOver05) IsNeedToWatch(liveMatch onexbet.LiveMatch) bool {
	return true
}

type FootballOver05Notes struct {
	PriceOver25           float64 `json:"Over 2.5 price"`
	MatchesAnalysed       int     `json:"matchesAnalysed"`
	HasGoalInMatches      int     `json:"hasGoalInMatches"`
	GoalsPercent          float64 `json:"goalsPercent"`
	ZeroDrawsInH2H        int     `json:"zeroDrawsInH2H"`
	ZeroDrawsPercentInH2H float64 `json:"zeroDrawsPercentInH2H"`
}

func (s FootballOver05) IsInteresting(report *TeamMatch) (notes interface{}, _ bool) {
	var (
		priceOver25      float64
		foundPriceOver25 bool
		//f                flashscore.TotalOffer
	)
	for _, total := range report.Odds.FullTimeTotal {
		if total.Total != "2.5" {
			continue
		}
		// 2.5
		for _, offer := range total.Offers {
			if offer.Bookmaker == flashscore.Bookmaker1xBet {
				priceOver25 = offer.Over
				foundPriceOver25 = true
				break
			}
		}

		if foundPriceOver25 {
			break
		} else {
			// 1xBet не нашли
			// Берем первый коэф.
			if len(total.Offers) > 0 {
				priceOver25 = total.Offers[0].Over
				foundPriceOver25 = true
			}
			break
		}
	}

	if priceOver25 > 1.7 {
		return
	}

	var (
		matchCount           int
		hasGoalsInMatchCount int
		zeroDrawsInH2HCount  int
		zeroDrawsPercent     float64
	)

	for _, match := range report.HomeTeamMatches {
		if match.HomeGoals > 0 || match.AwayGoals > 0 {
			hasGoalsInMatchCount++
		}
		matchCount++
	}

	for _, match := range report.AwayTeamMatches {
		if match.HomeGoals > 0 || match.AwayGoals > 0 {
			hasGoalsInMatchCount++
		}
		matchCount++
	}

	for _, match := range report.H2H {
		if match.HomeGoals > 0 || match.AwayGoals > 0 {
			hasGoalsInMatchCount++
		} else {
			zeroDrawsInH2HCount++
		}
		matchCount++
	}

	if matchCount == 0 {
		return
	}

	// h2hMatchCount        - 100%
	// zeroDrawsInH2HCount - x%
	if zeroDrawsInH2HCount > 0 {
		// Не более 2 сухих ничьи
		if zeroDrawsInH2HCount > 2 {
			return
		}

		zeroDrawsPercent = float64(len(report.H2H)*100) / float64(zeroDrawsInH2HCount)

		// Не более 20% сухих ничьих
		if zeroDrawsPercent > 20 {
			return
		}
	}

	// matchCount        - 100%
	// goalsInMatchCount - x%

	goalsPercent := float64(hasGoalsInMatchCount*100) / float64(matchCount)

	if goalsPercent < 80 {
		return
	}

	obj := FootballOver05Notes{
		PriceOver25:           priceOver25,
		MatchesAnalysed:       matchCount,
		HasGoalInMatches:      hasGoalsInMatchCount,
		GoalsPercent:          goalsPercent,
		ZeroDrawsInH2H:        zeroDrawsInH2HCount,
		ZeroDrawsPercentInH2H: zeroDrawsPercent,
	}

	//buf, _ := json.MarshalIndent(obj, "", "    ")

	return obj, true
}

func (s FootballOver05) GetTip(match *TeamMatch, upd onexbet.TeamLiveMatchData) (_ string, _ *BetDetails, _ TipCode) {
	if upd.CurrentTime == 0 {
		// ВАЖНО!
		// Матч еще не начался. Избегаем деления на 0 при вычислении attacksRatio
		return "матч не начался", nil, Waiting
	}

	// Прогнозы даем до 70 минуты включительно.
	maxTime := 70 * 60

	if upd.CurrentTime > maxTime {
		return "70 минут уже отыграли", nil, Unwatch
	}

	if upd.HomeGoals > 0 || upd.AwayGoals > 0 {
		// Если гол уже забили - выходим
		return "гол уже забили", nil, Unwatch
	}

	// Ищем тотал Больше 0.5
	// Минимальный курс
	minPrice := 1.5
	var (
		minPriceCheckPassed bool
		currentPrice        float64
	)

	for _, over := range upd.Total.Over {
		if over.Param == "0.5" {
			if over.Price < minPrice {
				return fmt.Sprintf("коэф. %.2f < %.2f", over.Price, minPrice), nil, Waiting
			}
			currentPrice = over.Price
			minPriceCheckPassed = true
			break
		}
	}

	if !minPriceCheckPassed {
		return "тотал 0.5 не найден", nil, Waiting
	}

	//
	attacks := upd.HomeAttacks + upd.AwayAttacks + upd.HomeDangerousAttacks + upd.AwayDangerousAttacks
	shotsOffTarget := upd.HomeShotsOffTarget + upd.AwayShotsOffTarget
	shotsOnTarget := upd.HomeShotsOnTarget + upd.AwayShotsOnTarget

	if attacks < 135 {
		return fmt.Sprintf("%d атак < 135", attacks), nil, Waiting
	}

	if shotsOffTarget < 6 {
		return fmt.Sprintf("%d shotsOffTarget < 6", shotsOffTarget), nil, Waiting
	}

	if shotsOnTarget < 4 {
		return fmt.Sprintf("%d shotsOnTarget < 4", shotsOnTarget), nil, Waiting
	}

	return "", &BetDetails{
		Market: MarketTotal,
		Side:   SideOver,
		Param:  "0.5",
		Price:  currentPrice,
	}, Bet
}

func (s FootballOver05) GetResult(tip model.Tip, stats onexbet.TeamMatchResult) (_ *TipResult) {
	//buf, _ := json.MarshalIndent(stats, "", "    ")
	//fmt.Printf("%s\n", buf)

	if stats.Status != onexbet.StatusMatchCompleted {
		return
	}

	res := new(TipResult)
	goals := stats.HomePoints + stats.AwayPoints
	if goals > 0 {
		res.Status = model.Won
	} else {
		res.Status = model.Lost
	}
	res.Result = fmt.Sprintf("счет: %d-%d", stats.HomePoints, stats.AwayPoints)
	return res
}

////////// P1 OVER 0.5

type FootballP1Over05 struct {
	id               int64
	notifyInTelegram bool
	isChampAccepted  func(string) bool
}

func NewFootballP1Over05(opt StrategyOptions) FootballP1Over05 {
	if opt.ID == 0 {
		panic("StrategyID not defined")
	}
	s := FootballP1Over05{}
	s.id = opt.ID
	s.notifyInTelegram = opt.NotifyInTelegram
	s.isChampAccepted = opt.IsChampAccepted
	return s
}

func (s FootballP1Over05) ID() int64 {
	return s.id
}

func (s FootballP1Over05) ShortName() string {
	return fmt.Sprintf("#%d H1 Over 0.5 M", s.id)
}

func (s FootballP1Over05) IsNotifyInTelegram() bool {
	return s.notifyInTelegram
}

func (s FootballP1Over05) GetTelegramTipPattern() string {
	return `Сигнал # %d.
Будет ГОЛ!
Алгоритм %d
Первый тайм, Тотал Больше 0.5
Футбол. %s. %s
%s - %s
Коэф. %.3f`
}

func (s FootballP1Over05) IsNeedToWatch(liveMatch onexbet.LiveMatch) bool {
	if liveMatch.CurrentPeriod == 1 {
		return true
	}
	return false
}

type isInterestingNotesFootballP1Over05 struct {
	PriceOver25           float64 `json:"Over 2.5 price"`
	MatchesAnalysed       int     `json:"matchesAnalysed"`
	HasGoalInP1Matches    int     `json:"hasGoalInP1Matches"`
	P1GoalsPercent        float64 `json:"p1GoalsPercent"`
	HasGoalInP1H2HMatches int     `json:"hasGoalInP1H2HMatches"`
	P1H2HGoalsPercent     float64 `json:"p1H2HGoalsPercent"`
}

func (s FootballP1Over05) IsInteresting(report *TeamMatch) (notes interface{}, _ bool) {
	var (
		priceOver25      float64
		foundPriceOver25 bool
	)

	for _, total := range report.Odds.FullTimeTotal {
		if total.Total != "2.5" {
			continue
		}
		// 2.5
		for _, offer := range total.Offers {
			if offer.Bookmaker == flashscore.Bookmaker1xBet {
				priceOver25 = offer.Over
				foundPriceOver25 = true
				break
			}
		}

		if foundPriceOver25 {
			break
		} else {
			// 1xBet не нашли
			// Берем первый коэф.
			if len(total.Offers) > 0 {
				priceOver25 = total.Offers[0].Over
				foundPriceOver25 = true
			}
			break
		}
	}

	if priceOver25 > 1.58 {
		return
	}

	var (
		hasStatsMatchCount     int
		hasGoalsInP1MatchCount int

		hasH2HStatsMatchCount     int
		hasGoalsInP1H2HMatchCount int
		p1H2HGoalsPercent         float64
	)

	for _, match := range report.HomeTeamMatches {
		if match.HasScoreByPeriods {
			hasStatsMatchCount++

			if match.P1HomeGoals > 0 || match.P1AwayGoals > 0 {
				hasGoalsInP1MatchCount++
			}
		}
	}

	for _, match := range report.AwayTeamMatches {
		if match.HasScoreByPeriods {
			hasStatsMatchCount++

			if match.P1HomeGoals > 0 || match.P1AwayGoals > 0 {
				hasGoalsInP1MatchCount++
			}
		}
	}

	for _, match := range report.H2H {
		if match.HasScoreByPeriods {
			hasH2HStatsMatchCount++

			if match.P1HomeGoals > 0 || match.P1AwayGoals > 0 {
				hasGoalsInP1H2HMatchCount++
			}
		}
	}

	if hasStatsMatchCount == 0 {
		return
	}

	// hasStatsMatchCount     - 100%
	// hasGoalsInP1MatchCount - x%

	p1GoalsPercent := float64(hasGoalsInP1MatchCount*100) / float64(hasStatsMatchCount)

	if p1GoalsPercent < 75 {
		return
	}

	if hasH2HStatsMatchCount > 0 {
		// hasH2HStatsMatchCount     - 100%
		// hasGoalsInP1H2HMatchCount - x%

		p1H2HGoalsPercent = float64(hasGoalsInP1H2HMatchCount*100) / float64(hasH2HStatsMatchCount)

		if p1H2HGoalsPercent < 80 {
			return
		}
	}

	obj := isInterestingNotesFootballP1Over05{
		PriceOver25:           priceOver25,
		MatchesAnalysed:       hasStatsMatchCount,
		HasGoalInP1Matches:    hasGoalsInP1MatchCount,
		P1GoalsPercent:        p1GoalsPercent,
		HasGoalInP1H2HMatches: hasGoalsInP1H2HMatchCount,
		P1H2HGoalsPercent:     p1H2HGoalsPercent,
	}

	//buf, _ := json.MarshalIndent(obj, "", "    ")

	return obj, true
}

func (s FootballP1Over05) GetTip(match *TeamMatch, upd onexbet.TeamLiveMatchData) (_ string, _ *BetDetails, _ TipCode) {
	if upd.CurrentTime == 0 {
		// ВАЖНО!
		// Матч еще не начался. Избегаем деления на 0 при вычислении attacksRatio
		return "матч не начался", nil, Waiting
	}

	// Прогнозы даем до 20 минуты включительно.
	maxTime := 20 * 60

	if upd.CurrentTime > maxTime {
		return "20 минут уже отыграли", nil, Unwatch
	}

	if upd.HomeGoals > 0 || upd.AwayGoals > 0 {
		// Если гол уже забили - выходим
		return "гол уже забили", nil, Unwatch
	}

	// Ищем тотал Больше 0.5
	// Минимальный курс
	minPrice := 1.5
	var (
		minPriceCheckPassed bool
		currentPrice        float64
	)

	for _, over := range upd.H1.Total.Over {
		if over.Param == "0.5" {
			if over.Price < minPrice {
				return fmt.Sprintf("коэф. %.2f < %.2f", over.Price, minPrice), nil, Waiting
			}
			currentPrice = over.Price
			minPriceCheckPassed = true
			break
		}
	}

	if !minPriceCheckPassed {
		return "тотал 0.5 не найден", nil, Waiting
	}

	// соотношение атак по времени >= 2.1 (за 10 минут от 21 атаки)
	attacks := upd.HomeAttacks + upd.AwayAttacks
	shotsOffTarget := upd.HomeShotsOffTarget + upd.AwayShotsOffTarget

	attacksRatio := float64(attacks*60) / float64(upd.CurrentTime)

	if attacksRatio < 2.1 {
		return fmt.Sprintf("отношение атак ко времени %.2f < 2.1", attacksRatio), nil, Waiting
	}

	if shotsOffTarget < 3 {
		return fmt.Sprintf("%d shotsOffTarget < 6", shotsOffTarget), nil, Waiting
	}

	return "", &BetDetails{
		Market: MarketTotalH1,
		Side:   SideOver,
		Param:  "0.5",
		Price:  currentPrice,
	}, Bet
}

func (s FootballP1Over05) GetResult(tip model.Tip, stats onexbet.TeamMatchResult) (_ *TipResult) {
	//buf, _ := json.MarshalIndent(stats, "", "    ")
	//fmt.Printf("%s\n", buf)

	h1, ok := stats.ScoreByPeriods[1]
	if !ok {
		return
	}

	_, ok = stats.ScoreByPeriods[2]
	if !ok {
		return
	}

	res := new(TipResult)
	h1TotalGoals := h1.HomePoints + h1.AwayPoints
	if h1TotalGoals > 0 {
		res.Status = model.Won
	} else {
		res.Status = model.Lost
	}
	res.Result = fmt.Sprintf("1й тайм: %d-%d", h1.HomePoints, h1.AwayPoints)
	return res
}

//////////////// OVER 1.5

type FootballOver15 struct {
	id               int64
	notifyInTelegram bool
	isChampAccepted  func(string) bool
}

func NewFootballOver15(opt StrategyOptions) FootballOver15 {
	if opt.ID == 0 {
		panic("StrategyID not defined")
	}
	s := FootballOver15{}
	s.id = opt.ID
	s.notifyInTelegram = opt.NotifyInTelegram
	s.isChampAccepted = opt.IsChampAccepted
	return s
}

func (s FootballOver15) ID() int64 {
	return s.id
}

func (s FootballOver15) ShortName() string {
	return fmt.Sprintf("#%d FT Over 1.5 M", s.id)
}

func (s FootballOver15) IsNotifyInTelegram() bool {
	return s.notifyInTelegram
}

func (s FootballOver15) GetTelegramTipPattern() string {
	return `Сигнал # %d.
Будет 2й ГОЛ!
Алгоритм %d
Тотал Больше 1.5
Футбол. %s. %s
%s - %s
Коэф. %.3f`
}

func (s FootballOver15) IsNeedToWatch(liveMatch onexbet.LiveMatch) bool {
	return true
}

type isInterestingNotesFootballOver15 struct {
	PriceOver25      float64 `json:"Over 2.5 price"`
	MatchesAnalysed  int     `json:"matchesAnalysed"`
	HasGoalInMatches int     `json:"hasGoalInMatches"`
	GoalsPercent     float64 `json:"goalsPercent"`
	FavoritePrice    float64 `json:"favoritePrice"`
	Favorite         string  `json:"favorite"`
}

func (s FootballOver15) IsInteresting(report *TeamMatch) (notes interface{}, _ bool) {
	var favoritePrice float64 = 2
	var favorite string

	// Проходим по всем ценам, каждый раз обновляя минимальную
	for _, offer := range report.Odds.Winner {
		if offer.Home < favoritePrice && offer.Home > 1.01 {
			favoritePrice = offer.Home
			favorite = "home"
		}

		if offer.Away < favoritePrice && offer.Away > 1.01 {
			favoritePrice = offer.Away
			favorite = "away"
		}
	}

	if favoritePrice > 1.4 {
		return
	}

	var (
		priceOver25      float64
		foundPriceOver25 bool
	)

	for _, total := range report.Odds.FullTimeTotal {
		if total.Total != "2.5" {
			continue
		}
		// 2.5
		for _, offer := range total.Offers {
			if offer.Bookmaker == flashscore.Bookmaker1xBet {
				priceOver25 = offer.Over
				foundPriceOver25 = true
				break
			}
		}

		if foundPriceOver25 {
			break
		} else {
			// 1xBet не нашли
			// Берем первый коэф.
			if len(total.Offers) > 0 {
				priceOver25 = total.Offers[0].Over
				foundPriceOver25 = true
			}
			break
		}
	}

	if priceOver25 > 1.7 {
		return
	}

	var (
		matchCount           int
		hasGoalsInMatchCount int
	)

	for _, match := range report.HomeTeamMatches {
		if match.HomeGoals > 0 || match.AwayGoals > 0 {
			hasGoalsInMatchCount++
		}
		matchCount++
	}

	for _, match := range report.AwayTeamMatches {
		if match.HomeGoals > 0 || match.AwayGoals > 0 {
			hasGoalsInMatchCount++
		}
		matchCount++
	}

	for _, match := range report.H2H {
		if match.HomeGoals > 0 || match.AwayGoals > 0 {
			hasGoalsInMatchCount++
		}
		matchCount++
	}

	if matchCount == 0 {
		return
	}

	// matchCount        - 100%
	// goalsInMatchCount - x%

	goalsPercent := float64(hasGoalsInMatchCount*100) / float64(matchCount)

	if goalsPercent < 75 {
		return
	}

	obj := isInterestingNotesFootballOver15{
		PriceOver25:      priceOver25,
		MatchesAnalysed:  matchCount,
		HasGoalInMatches: hasGoalsInMatchCount,
		GoalsPercent:     goalsPercent,
		FavoritePrice:    favoritePrice,
		Favorite:         favorite,
	}

	report.Favorite = favorite

	//buf, _ := json.MarshalIndent(obj, "", "    ")

	return obj, true
}

func (s FootballOver15) GetTip(match *TeamMatch, upd onexbet.TeamLiveMatchData) (_ string, _ *BetDetails, _ TipCode) {
	if upd.CurrentTime == 0 {
		// ВАЖНО!
		// Матч еще не начался. Избегаем деления на 0 при вычислении attacksRatio
		return "матч не начался", nil, Waiting
	}

	// Прогнозы даем до 70 минуты включительно.
	maxTime := 70 * 60

	if upd.CurrentTime > maxTime {
		return "70 минут уже отыграли", nil, Unwatch
	}

	goals := upd.HomeGoals + upd.AwayGoals

	if goals > 1 {
		// Если 2 гола уже забили - выходим
		return "забили более 1 гола", nil, Unwatch
	}

	if goals == 0 {
		return "счет 0-0", nil, Waiting
	}

	if (upd.HomeGoals == 1 && match.Favorite == "away") || (upd.AwayGoals == 1 && match.Favorite == "home") {
		// все ок, фаворит уступает - анализируем дальше
	} else {
		// забил фаворит - далее неинтересно
		return "забил фаворит", nil, Unwatch
	}

	// Ищем тотал Больше 1.5
	// Минимальный курс
	minPrice := 1.5
	var (
		minPriceCheckPassed bool
		currentPrice        float64
	)

	for _, over := range upd.Total.Over {
		if over.Param == "1.5" {
			if over.Price < minPrice {
				comment := fmt.Sprintf("коэф. %.2f < %.2f", over.Price, minPrice)
				return comment, nil, Waiting
			}
			currentPrice = over.Price
			minPriceCheckPassed = true
			break
		}
	}

	if !minPriceCheckPassed {
		return "тотал 1.5 не найден", nil, Waiting
	}

	//
	attacks := upd.HomeAttacks + upd.AwayAttacks + upd.HomeDangerousAttacks + upd.AwayDangerousAttacks
	shotsOffTarget := upd.HomeShotsOffTarget + upd.AwayShotsOffTarget
	shotsOnTarget := upd.HomeShotsOnTarget + upd.AwayShotsOnTarget

	if attacks < 125 {
		return fmt.Sprintf("%d атак < 125", attacks), nil, Waiting
	}

	if shotsOffTarget < 6 {
		return fmt.Sprintf("%d shotsOffTarget < 6", shotsOffTarget), nil, Waiting
	}

	if shotsOnTarget < 4 {
		return fmt.Sprintf("%d shotsOnTarget < 4", shotsOnTarget), nil, Waiting
	}

	return "", &BetDetails{
		Market: MarketTotal,
		Side:   SideOver,
		Param:  "1.5",
		Price:  currentPrice,
	}, Bet
}

func (s FootballOver15) GetResult(tip model.Tip, stats onexbet.TeamMatchResult) (_ *TipResult) {
	//buf, _ := json.MarshalIndent(stats, "", "    ")
	//fmt.Printf("%s\n", buf)

	if stats.Status != onexbet.StatusMatchCompleted {
		return
	}

	res := new(TipResult)
	goals := stats.HomePoints + stats.AwayPoints
	if goals > 1 {
		res.Status = model.Won
	} else {
		res.Status = model.Lost
	}
	res.Result = fmt.Sprintf("счет: %d-%d", stats.HomePoints, stats.AwayPoints)
	return res
}
