package qznn

import (
	"reflect"
	"testing"
	"time"

	"github.com/bwmarrin/snowflake"
	"github.com/shopspring/decimal"
	"github.com/spf13/viper"
	"gogs.daxia.dev/huanan/pkg.daxia.dev/db"
	"gorm.io/gorm"
	"nn.daxia.dev/model"
)

func TestGame_payout(t *testing.T) {
	viper.Set("gormlog", true)
	viper.Set("db.username", "root")
	viper.Set("db.password", "123456~")
	viper.Set("db.addr", "10.42.50.148:3306")
	viper.Set("db.name", "qznn")

	db.Init()

	db.GetDB().Model(model.User{}).Where("id = 22").Update("credits", 10000)
	db.GetDB().Model(model.User{}).Where("id = 23").Update("credits", 10000)

	type fields struct {
		RoomMap   map[int32]Room
		PlayerMap map[int32]Player
		IDGener   *snowflake.Node
		LogID     int64
	}
	type args struct {
		tx             *gorm.DB
		roomBaseAmount decimal.Decimal
		roomID         int32
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    map[int32]PayoutInfo
		wantErr bool
	}{
		{
			name: "normal",
			fields: fields{
				RoomMap: map[int32]Room{
					1: Room{
						ID:       1,
						Name:     "test",
						RoomType: int32(model.RoomTypeFree),
						ChairList: []Chair{
							Chair{
								ID:       0,
								PlayerID: 22,
							},
							Chair{
								ID:       1,
								PlayerID: 23,
							},
						},
						BaseAmount:      decimal.NewFromInt(3),
						Issue:           "123",
						Status:          RoomStatusOpen,
						StatusStartTime: time.Now().Unix(),
						ReadyCh:         make(chan bool),
						ChooseMasterCh:  make(chan bool),
						ChooseMulCh:     make(chan bool),
						OpenCh:          make(chan bool),
					},
				},
				PlayerMap: map[int32]Player{
					22: Player{
						ID:        22,
						Name:      "test_player22",
						Balance:   decimal.NewFromInt(200),
						Credits:   decimal.NewFromInt(200),
						RoomID:    1,
						IsMaster:  true,
						MasterMul: 3,
						Mul:       3,
						Status:    PlayerStatusOpen,
						CardList: NNCardList{
							Card1: Card{
								Suit: 1,
								Num:  5,
							},
							Card2: Card{
								Suit: 2,
								Num:  7,
							},
							Card3: Card{
								Suit: 3,
								Num:  8,
							},
							Card4: Card{
								Suit: 1,
								Num:  10,
							},
							Card5: Card{
								Suit: 4,
								Num:  11,
							},
						},
					},
					23: Player{
						ID:        23,
						Name:      "test_player23",
						Balance:   decimal.NewFromInt(200),
						Credits:   decimal.NewFromInt(200),
						RoomID:    1,
						IsMaster:  false,
						MasterMul: 3,
						Mul:       3,
						Status:    PlayerStatusOpen,
						CardList: NNCardList{
							Card1: Card{
								Suit: 1,
								Num:  13,
							},
							Card2: Card{
								Suit: 2,
								Num:  6,
							},
							Card3: Card{
								Suit: 3,
								Num:  9,
							},
							Card4: Card{
								Suit: 1,
								Num:  7,
							},
							Card5: Card{
								Suit: 4,
								Num:  3,
							},
						},
					},
				},
			},
			args: args{
				tx:             db.GetDB(),
				roomBaseAmount: decimal.NewFromInt(3),
				roomID:         1,
			},
			want: map[int32]PayoutInfo{
				22: {
					PlayerID: 22,
					Amount:   decimal.NewFromInt(81),
					IsMaster: true,
				},
				23: {
					PlayerID: 23,
					Amount:   decimal.NewFromInt(-81),
					IsMaster: false,
				},
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p := &Game{
				RoomMap:   tt.fields.RoomMap,
				PlayerMap: tt.fields.PlayerMap,
			}
			got, err := p.payout(tt.args.tx, tt.args.roomBaseAmount, tt.args.roomID)
			if (err != nil) != tt.wantErr {
				t.Errorf("Game.payout() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Game.payout() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGame_payout_庄没钱(t *testing.T) {
	viper.Set("gormlog", true)
	viper.Set("db.username", "root")
	viper.Set("db.password", "123456~")
	viper.Set("db.addr", "10.42.50.148:3306")
	viper.Set("db.name", "qznn")

	db.Init()

	db.GetDB().Model(model.User{}).Where("id = 22").Update("credits", 0)
	db.GetDB().Model(model.User{}).Where("id = 23").Update("credits", 10000)

	type fields struct {
		RoomMap   map[int32]Room
		PlayerMap map[int32]Player
		IDGener   *snowflake.Node
		LogID     int64
	}
	type args struct {
		tx             *gorm.DB
		roomBaseAmount decimal.Decimal
		roomID         int32
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    map[int32]PayoutInfo
		wantErr bool
	}{
		{
			name: "normal",
			fields: fields{
				RoomMap: map[int32]Room{
					1: Room{
						ID:       1,
						Name:     "test",
						RoomType: int32(model.RoomTypeFree),
						ChairList: []Chair{
							Chair{
								ID:       0,
								PlayerID: 22,
							},
							Chair{
								ID:       1,
								PlayerID: 23,
							},
						},
						BaseAmount:      decimal.NewFromInt(3),
						Issue:           "123",
						Status:          RoomStatusOpen,
						StatusStartTime: time.Now().Unix(),
						ReadyCh:         make(chan bool),
						ChooseMasterCh:  make(chan bool),
						ChooseMulCh:     make(chan bool),
						OpenCh:          make(chan bool),
					},
				},
				PlayerMap: map[int32]Player{
					22: Player{
						ID:        22,
						Name:      "test_player22",
						Balance:   decimal.NewFromInt(200),
						Credits:   decimal.NewFromInt(200),
						RoomID:    1,
						IsMaster:  true,
						MasterMul: 3,
						Mul:       3,
						Status:    PlayerStatusOpen,
						CardList: NNCardList{
							Card1: Card{
								Suit: 1,
								Num:  5,
							},
							Card2: Card{
								Suit: 2,
								Num:  7,
							},
							Card3: Card{
								Suit: 3,
								Num:  9,
							},
							Card4: Card{
								Suit: 1,
								Num:  10,
							},
							Card5: Card{
								Suit: 4,
								Num:  11,
							},
						},
					},
					23: Player{
						ID:        23,
						Name:      "test_player23",
						Balance:   decimal.NewFromInt(200),
						Credits:   decimal.NewFromInt(200),
						RoomID:    1,
						IsMaster:  false,
						MasterMul: 3,
						Mul:       3,
						Status:    PlayerStatusOpen,
						CardList: NNCardList{
							Card1: Card{
								Suit: 1,
								Num:  5,
							},
							Card2: Card{
								Suit: 2,
								Num:  7,
							},
							Card3: Card{
								Suit: 3,
								Num:  8,
							},
							Card4: Card{
								Suit: 1,
								Num:  10,
							},
							Card5: Card{
								Suit: 4,
								Num:  11,
							},
						},
					},
				},
			},
			args: args{
				tx:             db.GetDB(),
				roomBaseAmount: decimal.NewFromInt(3),
				roomID:         1,
			},
			want: map[int32]PayoutInfo{
				22: {
					PlayerID: 22,
					Amount:   decimal.Zero,
					IsMaster: true,
				},
				23: {
					PlayerID: 23,
					Amount:   decimal.Zero,
					IsMaster: false,
				},
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p := &Game{
				RoomMap:   tt.fields.RoomMap,
				PlayerMap: tt.fields.PlayerMap,
			}
			got, err := p.payout(tt.args.tx, tt.args.roomBaseAmount, tt.args.roomID)
			if (err != nil) != tt.wantErr {
				t.Errorf("Game.payout() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if !got[22].Amount.Equal(tt.want[22].Amount) {
				t.Errorf("Game.payout() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGame_payout_庄没钱2(t *testing.T) {
	viper.Set("gormlog", true)
	viper.Set("db.username", "root")
	viper.Set("db.password", "123456~")
	viper.Set("db.addr", "10.42.50.148:3306")
	viper.Set("db.name", "qznn")

	db.Init()

	db.GetDB().Model(model.User{}).Where("id = 22").Update("credits_qznn", 72)
	db.GetDB().Model(model.User{}).Where("id = 23").Update("credits_qznn", 10000)
	db.GetDB().Model(model.User{}).Where("id = 24").Update("credits_qznn", 10000)

	type fields struct {
		RoomMap   map[int32]Room
		PlayerMap map[int32]Player
		IDGener   *snowflake.Node
		LogID     int64
	}
	type args struct {
		tx             *gorm.DB
		roomBaseAmount decimal.Decimal
		roomID         int32
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    map[int32]PayoutInfo
		wantErr bool
	}{
		{
			name: "normal",
			fields: fields{
				RoomMap: map[int32]Room{
					1: Room{
						ID:       1,
						Name:     "test",
						RoomType: int32(model.RoomTypeFree),
						ChairList: []Chair{
							Chair{
								ID:       0,
								PlayerID: 22,
							},
							Chair{
								ID:       1,
								PlayerID: 23,
							},
							Chair{
								ID:       1,
								PlayerID: 24,
							},
						},
						BaseAmount:      decimal.NewFromInt(3),
						Issue:           "123",
						Status:          RoomStatusOpen,
						StatusStartTime: time.Now().Unix(),
						ReadyCh:         make(chan bool),
						ChooseMasterCh:  make(chan bool),
						ChooseMulCh:     make(chan bool),
						OpenCh:          make(chan bool),
					},
				},
				PlayerMap: map[int32]Player{
					22: Player{
						ID:        22,
						Name:      "test_player22",
						Balance:   decimal.NewFromInt(0),
						Credits:   decimal.NewFromInt(72),
						RoomID:    1,
						IsMaster:  true,
						MasterMul: 3,
						Mul:       1,
						Status:    PlayerStatusOpen,
						CardList:  CardList2NNCardList(getOpenNumList("48,10,37,22,0")),
					},
					23: Player{
						ID:        23,
						Name:      "test_player23",
						Balance:   decimal.NewFromInt(0),
						Credits:   decimal.NewFromInt(10000),
						RoomID:    1,
						IsMaster:  false,
						MasterMul: 2,
						Mul:       4,
						Status:    PlayerStatusOpen,
						CardList:  CardList2NNCardList(getOpenNumList("49,19,50,5,32")),
					},
					24: Player{
						ID:        24,
						Name:      "test_player24",
						Balance:   decimal.NewFromInt(0),
						Credits:   decimal.NewFromInt(10000),
						RoomID:    1,
						IsMaster:  false,
						MasterMul: 1,
						Mul:       1,
						Status:    PlayerStatusOpen,
						CardList:  CardList2NNCardList(getOpenNumList("14,4,45,21,51")),
					},
				},
			},
			args: args{
				tx:             db.GetDB(),
				roomBaseAmount: decimal.NewFromInt(3),
				roomID:         1,
			},
			want: map[int32]PayoutInfo{
				22: {
					PlayerID: 22,
					Amount:   decimal.NewFromInt(-72),
					IsMaster: true,
				},
				23: {
					PlayerID: 23,
					Amount:   decimal.NewFromInt(81),
					IsMaster: false,
				},
				24: {
					PlayerID: 24,
					Amount:   decimal.NewFromInt(-9),
					IsMaster: false,
				},
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p := &Game{
				RoomMap:   tt.fields.RoomMap,
				PlayerMap: tt.fields.PlayerMap,
			}
			got, err := p.payout(tt.args.tx, tt.args.roomBaseAmount, tt.args.roomID)
			if (err != nil) != tt.wantErr {
				t.Errorf("Game.payout() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if !got[22].Amount.Equal(tt.want[22].Amount) {
				t.Errorf("Game.payout() = %v, want %v", got, tt.want)
			}

			if !got[23].Amount.Equal(tt.want[23].Amount) {
				t.Errorf("Game.payout() = %v, want %v", got, tt.want)
			}

			if !got[24].Amount.Equal(tt.want[24].Amount) {
				t.Errorf("Game.payout() = %v, want %v", got, tt.want)
			}
		})
	}
}
