package mgr

import (
	"log/slog"
	"slgserver/constant"
	"slgserver/db"
	"slgserver/server/slgserver/model"
	"slgserver/server/slgserver/static_conf"
	"slgserver/server/slgserver/static_conf/facility"
	"slgserver/util"
	"sync"
	"time"
)

type roleResMgr struct {
	mutex    sync.RWMutex
	rolesRes map[int]*model.RoleRes
}

var RResMgr = &roleResMgr{
	rolesRes: make(map[int]*model.RoleRes),
}

//获取产量
func GetYield(rid int) model.Yield {
	by := RBMgr.GetYield(rid)
	cy := RFMgr.GetYield(rid)
	var y model.Yield

	y.Gold = by.Gold + cy.Gold + static_conf.Basic.Role.GoldYield
	y.Stone = by.Stone + cy.Stone + static_conf.Basic.Role.StoneYield
	y.Iron = by.Iron + cy.Iron + static_conf.Basic.Role.IronYield
	y.Grain = by.Grain + cy.Grain + static_conf.Basic.Role.GrainYield
	y.Wood = by.Wood + cy.Wood + static_conf.Basic.Role.WoodYield

	return y
}

//获取仓库容量
func GetDepotCapacity(rid int) int {
	return RFMgr.GetDepotCapacity(rid) + static_conf.Basic.Role.DepotCapacity
}

func (this *roleResMgr) Load() {

	rr := make([]*model.RoleRes, 0)
	err := db.MasterDB.Find(&rr)
	if err != nil {
		slog.Error("roleResMgr load role_res table error")
	}

	for _, v := range rr {
		this.rolesRes[v.RId] = v
	}

	go this.produce()

}

func (this *roleResMgr) Get(rid int) (*model.RoleRes, bool) {

	this.mutex.RLock()
	r, ok := this.rolesRes[rid]
	this.mutex.RUnlock()

	if ok {
		return r, true
	}

	m := &model.RoleRes{}
	ok, err := db.MasterDB.Table(new(model.RoleRes)).Where("rid=?", rid).Get(m)
	if ok {

		this.mutex.Lock()
		this.rolesRes[rid] = m
		this.mutex.Unlock()

		return m, true
	} else {
		if err == nil {
			slog.Warn("RoleRes not found", "rid", rid)
			return nil, false
		} else {
			slog.Warn("db error", "error", err)
			return nil, false
		}
	}
}

func (this *roleResMgr) Add(res *model.RoleRes) {

	this.mutex.Lock()
	this.rolesRes[res.RId] = res
	this.mutex.Unlock()
}

func (this *roleResMgr) TryUseNeed(rid int, need facility.NeedRes) int {

	this.mutex.RLock()
	rr, ok := this.rolesRes[rid]
	this.mutex.RUnlock()

	if ok {
		if need.Decree <= rr.Decree && need.Grain <= rr.Grain &&
			need.Stone <= rr.Stone && need.Wood <= rr.Wood &&
			need.Iron <= rr.Iron && need.Gold <= rr.Gold {
			rr.Decree -= need.Decree
			rr.Iron -= need.Iron
			rr.Wood -= need.Wood
			rr.Stone -= need.Stone
			rr.Grain -= need.Grain
			rr.Gold -= need.Gold

			rr.SyncExecute()
			return constant.OK
		} else {
			if need.Decree > rr.Decree {
				return constant.DecreeNotEnough
			} else {
				return constant.ResNotEnough
			}
		}
	} else {
		return constant.RoleNotExist
	}
}

//政令是否足够
func (this *roleResMgr) DecreeIsEnough(rid int, cost int) bool {

	this.mutex.RLock()
	rr, ok := this.rolesRes[rid]
	this.mutex.RUnlock()

	if ok {
		if rr.Decree >= cost {
			return true
		} else {
			return false
		}
	} else {
		return false
	}
}

func (this *roleResMgr) TryUseDecree(rid int, decree int) bool {

	this.mutex.RLock()
	rr, ok := this.rolesRes[rid]
	this.mutex.RUnlock()

	if ok {
		if rr.Decree >= decree {
			rr.Decree -= decree
			rr.SyncExecute()
			return true
		} else {
			return false
		}
	} else {
		return false
	}
}

//金币是否足够
func (this *roleResMgr) GoldIsEnough(rid int, cost int) bool {

	this.mutex.RLock()
	rr, ok := this.rolesRes[rid]
	this.mutex.RUnlock()

	if ok {
		if rr.Gold >= cost {
			return true
		} else {
			return false
		}
	} else {
		return false
	}
}

func (this *roleResMgr) TryUseGold(rid int, gold int) bool {

	this.mutex.RLock()
	rr, ok := this.rolesRes[rid]
	this.mutex.RUnlock()

	if ok {
		if rr.Gold >= gold {
			rr.Gold -= gold
			rr.SyncExecute()
			return true
		} else {
			return false
		}
	} else {
		return false
	}
}

func (this *roleResMgr) produce() {
	index := 1
	for true {
		t := static_conf.Basic.Role.RecoveryTime
		time.Sleep(time.Duration(t) * time.Second)
		this.mutex.RLock()

		// 收集需要更新的角色资源
		updateList := make([]*model.RoleRes, 0, len(this.rolesRes))
		for _, v := range this.rolesRes {
			//加判断是因为爆仓了，资源不无故减少
			capacity := GetDepotCapacity(v.RId)
			yield := GetYield(v.RId)
			needUpdate := false

			if v.Wood < capacity {
				v.Wood += util.MinInt(yield.Wood/6, capacity)
				needUpdate = true
			}

			if v.Iron < capacity {
				v.Iron += util.MinInt(yield.Iron/6, capacity)
				needUpdate = true
			}

			if v.Stone < capacity {
				v.Stone += util.MinInt(yield.Stone/6, capacity)
				needUpdate = true
			}

			if v.Grain < capacity {
				v.Grain += util.MinInt(yield.Grain/6, capacity)
				needUpdate = true
			}

			if v.Gold < capacity {
				v.Gold += util.MinInt(yield.Gold/6, capacity)
				needUpdate = true
			}

			if index%6 == 0 {
				if v.Decree < static_conf.Basic.Role.DecreeLimit {
					v.Decree += 1
					needUpdate = true
				}
			}

			if needUpdate {
				updateList = append(updateList, v)
			}
		}
		index++
		this.mutex.RUnlock()

		// 批量更新数据库 - 使用事务
		if len(updateList) > 0 {
			sess := db.MasterDB.NewSession()
			defer sess.Close()

			if err := sess.Begin(); err != nil {
				slog.Warn("begin transaction error", "error", err)
				continue
			}

			for _, v := range updateList {
				if _, err := sess.ID(v.RId).Cols("wood", "iron", "stone", "grain", "gold", "decree").Update(v); err != nil {
					slog.Warn("update role res error", "rid", v.RId, "error", err)
					sess.Rollback()
					goto CONTINUE
				}
			}

			if err := sess.Commit(); err != nil {
				slog.Warn("commit transaction error", "error", err)
			} else {
				slog.Debug("batch update role resources", "count", len(updateList))
			}
		}
	CONTINUE:
	}
}
