package model

import (
	"active/tools"
	"encoding/json"
	"errors"
	"strings"
	"time"

	"git.jiaxianghudong.com/go/logs"
	"git.jiaxianghudong.com/webs/pkg/dbx"
)

var errOpenIDEmpty = errors.New("openid can not be empty")

type FuncStatus struct {
	Val      int32 `json:"v"`  // 当前计数
	LastTime int64 `json:"lt"` // 上一次操作时间
}

// PlayerData 玩家信息
type PlayerData struct {
	//Source          string    `json:"source,omitempty"` // 用户来源
	//RegDate         time.Time `json:"rt,omitempty"`     // 用户注册时间
	// ADFailTime      tools.Time `json:"adft,omitempty"`  // 用户上次拉取广告失败的时间
	// LastFissionTime tools.Time `json:"l_ft,omitempty"`  // 最后一次拉新时间
	// LastADTime      tools.Time `json:"l_adt,omitempty"` // 最后一次看广告的时间

	// 用户累计计数
	// FissionUsers int32 `json:"fu"` // 总拉新人数
	//LoginDays           int32 `json:"ld"`     // 总登陆天数
	// ShareToTimeline     int32 `json:"stt"`   // 总分享到朋友圈次数
	// ShareToTimelineDays int32 `json:"d_stt"` // 总分享到朋友圈行为的发生天数
	// ShareToGroup        int32 `json:"stg"`   // 总分享到群次数
	// ShareToGroupDays    int32 `json:"d_stg"` // 总分享到群行为的发生天数

	// ShareToFriend     int32 `json:"stf"`   // 总分享到好友次数
	// ShareToFriendDays int32 `json:"d_stf"` // 总分享到好友行为的发生天数

	// AD        int32 `json:"ad"`       // 总看广告次数-小游戏
	// AppAD     int32 `json:"app_ad"`   // 总看广告次数-APP上观看
	// ADDays    int32 `json:"d_ad"`     // 总看广告行为的发生天数(小程序)
	// AppADDays int32 `json:"d_app_ad"` // 总看广告行为的发生天数（APP）

	// 用户本日计数
	// ShareRejectCount     int32 `json:"src"`        // 当前分享被拒次数, 成功后需清0
	// TodayShareToFriend   int32 `json:"t_stf"`      // 每日分享到指定好友数
	// TodayShareToGroup    int32 `json:"t_stg"`      // 本日分享到群的次数
	// TodayShareToTimeline int32 `json:"t_stt"`      // 本日分享到朋友圈的次数
	// TodayAD              int32 `json:"t_ad"`       // 本日看广告的次数(小程序)
	// TodayAppAD           int32 `json:"t_app_ad"`   // 本日看广告的次数（APP）
	// TodayFissionUsers    int32 `json:"t_fu"`       // 本日拉新人数
	UpdateTime       tools.Time `json:"up,omitempty"` // 数据更新时间
	TodayAwardShares int32      `json:"d_award_s"`    // 奖励埋点分享次数
	TodayAwardAds    int32      `json:"d_award_ad"`   // 奖励埋点广告次数

	// 用户处理用户拉新分享次数控制
	// FissionUserShareCount int32 `json:"fusc"` // 未拉新的分享次数

	// 用户功能状态
	FuncStatusMap map[string]*FuncStatus `json:"fsm,omitempty"` // map[功能标识符]*funcStatus
}

// Player 玩家 数据表
type Player struct {
	ID         int64      `sql:"id" json:"id"`
	MchID      string     `sql:"mch_id" json:"mch_id"`
	OpenID     string     `sql:"openid" json:"openid"`
	Data       PlayerData `sql:"-" json:"-"`
	UpdateTime string     `sql:"update" json:"update"`
}

// GetPlayerData 获取数据
func (p *Player) GetPlayerData() error {
	const strSQL = "SELECT `id`, `data`, `update` FROM players WHERE `openid`=? AND `mch_id`=? LIMIT 1"
	if p.OpenID != "" {
		var data []byte
		if err := dbx.MySQL.QueryRow(strSQL, p.OpenID, p.MchID).Scan(&p.ID, &data, &p.UpdateTime); err != nil {
			return err
		}

		if err := json.Unmarshal(data, &p.Data); err != nil {
			return err
		}
		now := time.Now()
		last := time.Time(p.Data.UpdateTime)

		// 不是当天，则重新计数
		if now.Year() != last.Year() || now.YearDay() != last.YearDay() {
			p.Data.TodayAwardAds = 0
			p.Data.TodayAwardShares = 0
			logs.Debug("重制时间: %v", last)
			// p.Data.ShareRejectCount = 0
			// p.Data.TodayAppAD = 0
			// p.Data.TodayAD = 0
			// p.Data.TodayFissionUsers = 0
			// p.Data.TodayShareToFriend = 0
			// p.Data.TodayShareToGroup = 0
			// p.Data.TodayShareToTimeline = 0
		}
		return nil
	}
	return errOpenIDEmpty
}

// GetPlayerByID
func GetPlayerByID(p *Player) error {
	const strSQL = "SELECT `id`, `data`, `update` FROM players WHERE `id`=? LIMIT 1"
	if p.OpenID != "" {
		row := dbx.MySQL.QueryRow(strSQL, p.ID)
		var data []byte
		if err := row.Scan(&p.ID, &data, &p.UpdateTime); err != nil {
			return err
		}

		return json.Unmarshal(data, &p.Data)
	}
	return errOpenIDEmpty
}

// Save 将玩家数据落盘
func (p *Player) Save() error {
	now := time.Now()
	p.Data.UpdateTime = tools.Time(now)
	data, err := json.Marshal(p.Data)
	if err != nil {
		return err
	}

	const strUpdate = "UPDATE players SET `data`=?, `update`=? WHERE `mch_id`=? AND `openid`=?"
	const strInsert = "INSERT INTO players(`mch_id`,`openid`, `data`, `update`) VALUES(?,?,?,?)"
	nowStr := tools.Time(now).String()

	res, err := dbx.MySQL.Exec(strInsert, p.MchID, p.OpenID, data, nowStr)
	if err == nil {
		if p.ID == 0 {
			p.ID, err = res.LastInsertId()
			return err
		}
		return nil
	}

	if strings.Contains(err.Error(), "Duplicate entry") {
		_, err := dbx.MySQL.Exec(strUpdate, data, nowStr, p.MchID, p.OpenID)
		return err
	}

	return err
}
