package model

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"gogs.daxia.dev/huanan/pkg.daxia.dev/db"
	"gorm.io/gorm"
)

type GameOpenLog struct {
	gorm.Model

	Issue      string `gorm:"type:varchar(25);comment:'期号'"`
	GameID     int32  `gorm:"type:int;comment:'游戏ID'"`
	GameName   string `gorm:"type:varchar(255);comment:'游戏名称'"`
	OpenResult string `gorm:"type:varchar(255);comment:'开奖结果'"`
	Url        string `gorm:"type:longtext;comment:'获取的URL'"`
	Hash       string `gorm:"type:varchar(255);comment:'获取到的Block Hash'"`
	Code5      string `gorm:"type:varchar(25);comment:'5个开奖号码'"`
	Code10     string `gorm:"type:varchar(25);comment:'10个开奖号码'"`
}

func (GameOpenLog) TableName() string {
	return "game_open_log"
}

func (p GameOpenLog) Init() error {
	var err error

	if db.GetDB().Migrator().HasTable(p) {
		return nil
	}

	err = db.GetDB().Migrator().CreateTable(p)
	if err != nil {
		logrus.Fatal(err)
		return err
	}

	err = db.GetDB().Exec("create unique index idx_game_id_issue on game_open_log (game_id, issue)").Error
	if err != nil {
		return err
	}

	return nil
}

func (p *GameOpenLog) GetByIssue(issueStr string) error {
	gameID := viper.GetInt32("game_id")

	err := db.GetDB().Model(p).Where("game_id = ? and issue = ?", gameID, issueStr).First(p).Error
	if err != nil {
		logrus.Error(err)
		return err
	}

	return nil
}

func (p GameOpenLog) GetListByIssueList(issueStrList []string) ([]GameOpenLog, error) {
	gameID := viper.GetInt32("game_id")

	gameOpenLogListModel := make([]GameOpenLog, 0)
	err := db.GetDB().Model(p).Where("game_id = ? and issue in ?", gameID, issueStrList).Scan(&gameOpenLogListModel).Error
	if err != nil {
		logrus.Error(err)
		return nil, err
	}

	return gameOpenLogListModel, nil
}

func (p GameOpenLog) GetLastItems(limit int) ([]GameOpenLog, error) {
	gameID := viper.GetInt32("game_id")
	gameOpenLogListModel := make([]GameOpenLog, 0)

	err := db.GetDB().Model(p).Where("game_id = ? and code5 <> ''", gameID).
		Order("id desc").Limit(limit).Scan(&gameOpenLogListModel).Error

	if err != nil {
		return nil, err
	}

	return gameOpenLogListModel, nil
}

func (p *GameOpenLog) GetNumber() string {
	gameID := viper.GetInt32("game_id")
	isRndNum := viper.GetBool("is_rnd_num")
	if isRndNum {
		if gameID == 10 {
			rndList := []string{
				"1,4,7",
				"1,4,8",
				"1,4,9",
				"2,4,9",
			}

			openNumberList, err := extractCode5NumberList(p.Code5)
			if err != nil {
				logrus.Error(err)
				return ""
			}

			total := openNumberList[0] + openNumberList[1] + openNumberList[2]
			return rndList[total%4]
		}
	}

	if gameID == 10 || gameID == 11 {
		openNumberList, err := extractCode5NumberList(p.Code5)
		if err != nil {
			logrus.Error(err)
			return ""
		}

		if len(openNumberList) < 3 {
			return ""
		}

		return intListJoin(openNumberList[len(openNumberList)-3:], ",")
	}

	if gameID == 200 {
		if len(p.Code5) != 5 {
			return ""
		}

		return p.Code5[4:]
	}

	if gameID == 12 || gameID == 8 || gameID == 13 {
		if p.Hash == "" {
			return ""
		}
		openNumberList, err := extractCode5NumberList(p.Code5)
		if err != nil {
			logrus.Error(err)
			return ""
		}

		return intListJoin(openNumberList, ",")
	}

	//骰宝
	if gameID == 14 {
		openNumberList, err := extractCode3NumberList(p.Code5)
		if err != nil {
			logrus.Error(err)
			return ""
		}

		if len(openNumberList) < 3 {
			return ""
		}

		return intListJoin(openNumberList[len(openNumberList)-3:], ",")
	}

	return p.Code10
}

func (p GameOpenLog) Exists(issueStr string) (bool, error) {
	var err error
	gameID := viper.GetInt32("game_id")

	count := int64(0)
	err = db.GetDB().Model(p).Where("issue = ? and game_id = ?", issueStr, gameID).Count(&count).Error
	if err != nil {
		logrus.Error(err, issueStr)
		return false, err
	}

	return count != 0, nil
}

func extractCodeNumberList13(code10 string) ([]int64, error) {
	var err error

	codeList := strings.Split(code10, ",")
	codeListLen := len(codeList)
	codeNumberList := make([]int64, codeListLen)
	for index, item := range codeList {
		var number int64

		number, err = strconv.ParseInt(string(item), 10, 16)
		if err != nil {
			return nil, errors.New("解析号码失败:" + code10)
		}

		codeNumberList[index] = number
	}

	return codeNumberList, nil
}

func extractCode5NumberList(code5 string) ([]int64, error) {
	var err error

	codeList := []byte(code5)
	if len(codeList) != 5 {
		return nil, errors.New("code5不是5位数字:" + code5)
	}

	codeNumberList := make([]int64, 5)
	for index, item := range codeList {
		var number int64

		number, err = strconv.ParseInt(string(item), 10, 16)
		if err != nil {
			return nil, errors.New("解析号码失败:" + code5)
		}

		codeNumberList[index] = number
	}

	return codeNumberList, nil
}

func extractCode3NumberList(code3 string) ([]int64, error) {
	var err error

	codeList := []byte(code3)
	if len(codeList) != 3 {
		return nil, errors.New("code3不是3位数字:" + code3)
	}

	codeNumberList := make([]int64, 3)
	for index, item := range codeList {
		var number int64

		number, err = strconv.ParseInt(string(item), 10, 16)
		if err != nil {
			return nil, errors.New("解析号码失败:" + code3)
		}

		codeNumberList[index] = number
	}

	return codeNumberList, nil
}

func intListJoin(intList []int64, sep string) string {
	stringList := make([]string, len(intList))
	for key, item := range intList {
		stringList[key] = fmt.Sprintf("%d", item)
	}

	return strings.Join(stringList, sep)
}
