package service

import (
	"errors"
	"go-admin/common/utils"
	"sort"
	"strconv"

	"github.com/go-admin-team/go-admin-core/sdk/service"
	"gorm.io/gorm"

	"go-admin/app/operate/models"
	"go-admin/app/operate/service/dto"
	"go-admin/common/actions"
	cDto "go-admin/common/dto"
)

type OrgTeamTeam struct {
	service.Service
}

// GetPage 获取OrgMatch列表
func (e *OrgTeamTeam) GetPage(c *dto.OrgTeamTeamGetPageReq, p *actions.DataPermission, list *[]dto.OrgTeamTeamGetPageReply, count *int64) error {
	var err error

	err = e.Orm.Table("org_match_team_player as omtp").
		Select("omtp.team_id, ol.league_name, om.season_id, os.season_name, omtp.rounds,"+
			"sum(omtp.scoring)as scoring, sum(omtp.rebound)as rebound, sum(omtp.assist)as assist, sum(omtp.steal)as steal, sum(omtp.free_throw)as free_throw,"+
			"sum(omtp.block_shot)as block_shot, sum(omtp.foul)as foul, sum(omtp.two_point_shot)as two_point_shot, sum(omtp.three_point_shot)as three_point_shot").
		Joins("left join org_match as om on om.id = omtp.match_id and omtp.rounds = om.rounds").
		Joins("left join org_league as ol on ol.id = om.league_id").
		Joins("left join org_season as os on os.id = om.season_id").
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
			actions.Permission("otmp", p),
			cDto.PassDel("omtp"),
		).
		Where("omtp.team_id=?", c.TeamId).
		Group("omtp.match_id").
		Find(list).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		e.Log.Errorf("OrgMatchService GetPage error:%s \r\n", err)
		return err
	}
	return nil
}

// GetPage 获取OrgMatch列表
func (e *OrgTeamTeam) GetPageForTeam(seasonId string) (error, []models.OrgMatchTeamPlayer, int64) {
	var err error
	list := make([]models.OrgMatchTeamPlayer, 0)
	var count int64 = 0
	err = e.Orm.Table("org_match_team_player as omtp").
		Select("omtp.team_id, om.match_start_time, om.rounds, om.grouping," +
			"sum(omtp.scoring)as scoring," +
			"sum(omtp.rebound)as rebound," +
			"sum(omtp.assist)as assist," +
			"sum(omtp.steal)as steal," +
			"sum(omtp.free_throw)as free_throw," +
			"sum(omtp.block_shot)as block_shot," +
			"sum(omtp.foul)as foul," +
			"sum(omtp.two_point_shot)as two_point_shot," +
			"sum(omtp.three_point_shot)as three_point_shot").
		Joins("left join org_match as om on om.id = omtp.match_id and omtp.rounds = om.rounds").
		Scopes(cDto.SetWhere("om", "season_id", seasonId)).
		Group("omtp.match_id").
		Find(list).Count(&count).Error

	if err != nil {
		e.Log.Errorf("OrgMatchService GetPage error:%s \r\n", err)
		return err, nil, 0
	}
	return nil, list, count
}

// GetPage 获取OrgMatchEvaluate列表
func (e *OrgTeamTeam) GetMatchInfo(id string, p *actions.DataPermission, data *cDto.PageMatchInfo) error {
	var err error

	err = e.Orm.Table("org_match_team_player as omtp").
		Select("omtp.team_id, omtp.match_id, ol.league_name, os.season_name,"+
			"oc.club_name, ot.team_name, omtp.player_id, om.season_id").
		Joins("left join org_club as oc on omtp.club_id = oc.id").
		Joins("left join org_team as ot on omtp.team_id = ot.id").
		Joins("left join org_match as om on omtp.match_id = om.id").
		Joins("left join org_league as ol on ol.id = om.league_id").
		Joins("left join org_season as os on os.id = om.season_id").
		Scopes(
			actions.Permission("omtp", p),
		).
		Where("omtp.team_id=?", id).
		First(data).Error
	if err != nil {
		e.Log.Errorf("OrgMatchService GetMatchInfo error:%s \r\n", err)
		return err
	}
	return nil
}

func (e *OrgTeamTeam) GetRoundsScoring(teamId string, matchId string, data *[]cDto.RoundsScoring) error {
	var err error

	err = e.Orm.Table("org_match_team_player as omtp").
		Select("omtp.team_id, om.match_start_time, om.rounds, om.grouping, ot.team_name as other_team_name,"+
			"sum(omtp.scoring)as scoring,"+
			"sum(omtp.rebound)as rebound,"+
			"sum(omtp.assist)as assist,"+
			"sum(omtp.steal)as steal,"+
			"sum(omtp.free_throw)as free_throw,"+
			"sum(omtp.block_shot)as block_shot,"+
			"sum(omtp.foul)as foul,"+
			"sum(omtp.two_point_shot)as two_point_shot,"+
			"sum(omtp.three_point_shot)as three_point_shot").
		Joins("left join org_team as ot on omtp.other_team_id = ot.id").
		Joins("left join org_match as om on om.id = omtp.match_id and omtp.rounds = om.rounds").
		Scopes(
			cDto.SetWhere("omtp", "team_id", teamId),
			cDto.SetWhere("omtp", "match_id", matchId),
		).
		Group("omtp.match_id").
		Find(data).Error
	if err != nil {
		e.Log.Errorf("OrgMatchService GetRoundsScoring error:%s \r\n", err)
		return err
	}
	return nil
}

func (e *OrgTeamTeam) statisticsScoring(teamId string, rounds string, seasonId string, statistics string, data *cDto.TotalScoring) error {
	var err error
	field := ""

	field += "sum(omtp.scoring)as scoring," +
		"sum(omtp.rebound)as rebound," +
		"sum(omtp.assist)as assist," +
		"sum(omtp.steal)as steal," +
		"sum(omtp.free_throw)as free_throw," +
		"sum(omtp.block_shot)as block_shot," +
		"sum(omtp.foul)as foul," +
		"sum(omtp.two_point_shot)as two_point_shot," +
		"sum(omtp.three_point_shot)as three_point_shot"

	err = e.Orm.Table("org_match_team_player as omtp").
		Joins("left join org_match as om on omtp.match_id = om.id and omtp.rounds = om.rounds").
		Select(field).
		Where("omtp.team_id = ?", teamId).
		Scopes(cDto.SetWhere("om", "season_id", seasonId)).
		First(data).Error

	if statistics == "avg" {
		var teamCount int64 = 0
		err = e.Orm.Table("org_match_team_player as omtp").
			Joins("left join org_match as om on omtp.match_id = om.id and omtp.rounds = om.rounds").
			Select(field).
			Scopes(cDto.SetWhere("om", "season_id", seasonId)).
			Count(&teamCount).Error

		data.Scoring = utils.GetAvg(data.Scoring, teamCount)
		data.Rebound = utils.GetAvg(data.Rebound, teamCount)
		data.Assist = utils.GetAvg(data.Assist, teamCount)
		data.Steal = utils.GetAvg(data.Steal, teamCount)
		data.FreeThrow = utils.GetAvg(data.FreeThrow, teamCount)
		data.BlockShot = utils.GetAvg(data.BlockShot, teamCount)
		data.Foul = utils.GetAvg(data.Foul, teamCount)
		data.TwoPointShot = utils.GetAvg(data.TwoPointShot, teamCount)
		data.ThreePointShot = utils.GetAvg(data.ThreePointShot, teamCount)
	}

	if err != nil {
		e.Log.Errorf("OrgMatchService GetTotalScoring error:%s \r\n", err)
		return err
	}
	return nil
}

// Get 获取OrgMatchEvaluate对象
func (e *OrgTeamTeam) GetTotalScoring(playerId string, rounds string, seasonId string, data *[]cDto.TotalScoring) error {
	replyGetTotalScoring1 := new(cDto.TotalScoring)
	e.statisticsScoring(playerId, rounds, "0", "sum", replyGetTotalScoring1)
	*data = append(*data, *replyGetTotalScoring1)

	replyGetTotalScoring2 := new(cDto.TotalScoring)
	e.statisticsScoring(playerId, rounds, "0", "avg", replyGetTotalScoring2)
	*data = append(*data, *replyGetTotalScoring2)

	replyGetTotalScoring3 := new(cDto.TotalScoring)
	e.statisticsScoring(playerId, rounds, seasonId, "sum", replyGetTotalScoring3)
	*data = append(*data, *replyGetTotalScoring3)

	replyGetTotalScoring4 := new(cDto.TotalScoring)
	e.statisticsScoring(playerId, rounds, seasonId, "avg", replyGetTotalScoring4)
	*data = append(*data, *replyGetTotalScoring4)

	replyGetTotalScoring5 := new(cDto.TotalScoring)
	e.statisticsRankingList(playerId, seasonId, replyGetTotalScoring5)
	*data = append(*data, *replyGetTotalScoring5)

	return nil
}

func (e *OrgTeamTeam) statisticsRankingList(playerId string, seasonId string, scoring *cDto.TotalScoring) error {

	replyGetPlayerRank := make([]models.OrgMatchTeamPlayer, 0)
	err := e.statisticsRanking(seasonId, &replyGetPlayerRank)
	if err != nil {
		e.Log.Errorf("OrgMatchService GetTotalScoring error:%s \r\n", err)
		return err
	}
	e.rankingScoring(replyGetPlayerRank, playerId, scoring)
	e.rankingRebound(replyGetPlayerRank, playerId, scoring)
	e.rankingAssist(replyGetPlayerRank, playerId, scoring)
	e.rankingSteal(replyGetPlayerRank, playerId, scoring)
	e.rankingFreeThrow(replyGetPlayerRank, playerId, scoring)
	e.rankingBlockShot(replyGetPlayerRank, playerId, scoring)
	e.rankingFoul(replyGetPlayerRank, playerId, scoring)
	e.rankingTwoPointShot(replyGetPlayerRank, playerId, scoring)
	e.rankingThreePointShot(replyGetPlayerRank, playerId, scoring)

	return nil
}

func (e *OrgTeamTeam) rankingScoring(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].Scoring) > utils.StringToFloat(replyGetPlayerRank[j].Scoring)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.Scoring = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingRebound(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].Rebound) > utils.StringToFloat(replyGetPlayerRank[j].Rebound)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.Rebound = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingAssist(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].Assist) > utils.StringToFloat(replyGetPlayerRank[j].Assist)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.Assist = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingSteal(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].Steal) > utils.StringToFloat(replyGetPlayerRank[j].Steal)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.Steal = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingFreeThrow(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].FreeThrow) > utils.StringToFloat(replyGetPlayerRank[j].FreeThrow)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.FreeThrow = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingBlockShot(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].BlockShot) > utils.StringToFloat(replyGetPlayerRank[j].BlockShot)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.BlockShot = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingFoul(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].Foul) > utils.StringToFloat(replyGetPlayerRank[j].Foul)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.Foul = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingTwoPointShot(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].TwoPointShot) > utils.StringToFloat(replyGetPlayerRank[j].TwoPointShot)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.TwoPointShot = strconv.Itoa(k + 1)
		}
	}
}
func (e *OrgTeamTeam) rankingThreePointShot(replyGetPlayerRank []models.OrgMatchTeamPlayer, playerId string, scoring *cDto.TotalScoring) {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].ThreePointShot) > utils.StringToFloat(replyGetPlayerRank[j].ThreePointShot)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == playerId {
			scoring.ThreePointShot = strconv.Itoa(k + 1)
		}
	}
}

func (e *OrgTeamTeam) statisticsRanking(seasonId string, data *[]models.OrgMatchTeamPlayer) error {
	var err error
	field := "omtp.team_id," +
		"sum(omtp.scoring)as scoring," +
		"sum(omtp.rebound)as rebound," +
		"sum(omtp.assist)as assist," +
		"sum(omtp.steal)as steal," +
		"sum(omtp.free_throw)as free_throw," +
		"sum(omtp.block_shot)as block_shot," +
		"sum(omtp.foul)as foul," +
		"sum(omtp.two_point_shot)as two_point_shot," +
		"sum(omtp.three_point_shot)as three_point_shot"
	err = e.Orm.Table("org_match_team_player as omtp").
		Select(field).
		Joins("left join org_match as om on omtp.match_id = om.id and omtp.rounds = om.rounds").
		Where("om.season_id = ?", seasonId).
		Group("omtp.team_id").
		Find(&data).Error

	if err != nil {
		e.Log.Errorf("OrgMatchService GetTotalScoring error:%s \r\n", err)
		return err
	}
	return nil
}

// Get 获取OrgMatchEvaluate对象
func (e *OrgTeamTeam) Get(d *dto.OrgMatchEvaluateGetReq, p *actions.DataPermission, model *models.OrgMatchEvaluate) error {
	var data models.OrgMatchEvaluate

	err := e.Orm.Model(&data).
		Scopes(
			actions.Permission(data.TableName(), p),
		).
		First(model, d.GetId()).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		e.Log.Errorf("Service GetOrgMatchEvaluate error:%s \r\n", err)
		return err
	}
	if err != nil {
		e.Log.Errorf("db error:%s", err)
		return err
	}
	return nil
}

func (e *OrgTeamTeam) GetRankForGetPage(seasonId string, teamId string) string {
	replyGetPlayerRank := make([]models.OrgMatchTeamPlayer, 0)
	err := e.statisticsRanking(seasonId, &replyGetPlayerRank)
	if err != nil {
		e.Log.Errorf("OrgMatchService GetTotalScoring error:%s \r\n", err)
		return "0"
	}
	return e.rankingForGetPage(replyGetPlayerRank, teamId)
}

func (e *OrgTeamTeam) rankingForGetPage(replyGetPlayerRank []models.OrgMatchTeamPlayer, teamId string) string {
	sort.Slice(replyGetPlayerRank, func(i, j int) bool {
		return utils.StringToFloat(replyGetPlayerRank[i].Scoring) > utils.StringToFloat(replyGetPlayerRank[j].Scoring)
	})
	for k, v := range replyGetPlayerRank {
		if v.TeamId == teamId {
			return strconv.Itoa(k + 1)
		}
	}
	return "0"
}