package restriction

import (
	"context"
	"kami/internal/dao"
	"kami/internal/model"
	"kami/internal/model/do"
	"kami/internal/model/entity"
	"kami/utility/config"
	"kami/utility/utils"

	"github.com/duke-git/lancet/v2/pointer"
	"github.com/duke-git/lancet/v2/slice"
	"github.com/gogf/gf/v2/database/gdb"
)

// SaveDeviceInfo 存储现有的设备
func (i *sRestriction) SaveDeviceInfo(ctx context.Context, input *model.RestrictionDeviceInput) (id int64, err error) {
	//保存设备信息
	err = config.GetDatabaseV1().Ctx(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		accessId, err2 := i.GetOrSetAccessRecord(ctx, do.V1RestrictClientAccessRecord{
			VisitorId:   input.DeviceID,
			DeviceModel: input.DeviceModel,
			UserAgent:   input.UserAgent,
			IsUseProxy:  slice.Contain(input.IPs, input.RemoteIP),
		}, tx)
		if err2 != nil {
			return err2
		}
		//保存每次的访问信息
		newId := utils.GenerateRandomUUID()
		//保存远程IP
		for _, ip := range input.IPs {
			if err2 = i.SaveDeviceIPRelation(ctx, ip, false, accessId, newId, tx); err2 != nil {
				return err2
			}
		}
		//保存实际IP
		err2 = i.SaveDeviceIPRelation(ctx, input.RemoteIP, true, accessId, newId, tx)
		return err2
	})
	return
}

// SaveDeviceIPRelation 保存IP关联关系
func (i *sRestriction) SaveDeviceIPRelation(ctx context.Context, ip string, isRemoteIP bool, accessId int, sessionId string, tx gdb.TX) (err error) {
	output, _ := i.GetOrSetIPRecord(ctx, ip, tx)
	m := dao.V1RestrictClientAccessIpRelation.Ctx(ctx).DB(config.GetDatabaseV1())
	if tx != nil {
		m = m.TX(tx)
	}
	if !pointer.IsNil(output) {
		_, err = m.Insert(do.V1RestrictClientAccessIpRelation{
			Ip:                           ip,
			IsRemoteIp:                   isRemoteIP,
			RestrictIpRecordId:           output.Id,
			RestrictClientAccessRecordId: accessId,
			SessionId:                    sessionId,
		})
	}
	return
}

func (i *sRestriction) GetOrSetAccessRecord(ctx context.Context, input do.V1RestrictClientAccessRecord, tx gdb.TX) (accessId int, err error) {
	var (
		db     = dao.V1RestrictClientAccessRecord.Ctx(ctx).DB(config.GetDatabaseV1())
		column = dao.V1RestrictClientAccessRecord.Columns()
	)
	if tx != nil {
		db = db.TX(tx)
	}
	var data entity.V1RestrictClientAccessRecord
	err = utils.HandleNoRowsError(db.Where(column.VisitorId, input.VisitorId).Scan(&data))
	if !pointer.IsNil(data) && data.Id != 0 {
		accessId = int(data.Id)
		return
	}
	accessIdInt, err := db.InsertAndGetId(input)
	accessId = int(accessIdInt)
	return
}

// CheckIsDeviceUseProxy 判断使用当前IP访问时候是不是使用代理，取最后一次
func (i *sRestriction) CheckIsDeviceUseProxy(ctx context.Context, deviceId, ip string) (isUse bool) {
	var (
		db     = dao.V1RestrictClientAccessRecord.Ctx(ctx).DB(config.GetDatabaseV1())
		column = dao.V1RestrictClientAccessRecord.Columns()
	)
	isUse = false
	clientAccess := entity.V1RestrictClientAccessRecord{}
	err := utils.HandleNoRowsError(db.Where(column.VisitorId, deviceId).Scan(&clientAccess))
	if err != nil {
		return
	}
	var (
		relationDb     = dao.V1RestrictClientAccessIpRelation.Ctx(ctx).DB(config.GetDatabaseV1())
		relationColumn = dao.V1RestrictClientAccessIpRelation.Columns()
	)
	relation := entity.V1RestrictClientAccessIpRelation{}
	err = utils.HandleNoRowsError(relationDb.Where(relationColumn.RestrictClientAccessRecordId, clientAccess.Id).OrderDesc(relationColumn.Id).
		Where(relationColumn.Ip, ip).Scan(&relation))
	if err != nil {
		return
	}
	relations := make([]entity.V1RestrictClientAccessIpRelation, 0)
	err = utils.HandleNoRowsError(relationDb.Where(relationColumn.SessionId, relation.SessionId).Scan(&relations))
	if err != nil {
		return
	}
	return slice.CountBy(relations, func(index int, item entity.V1RestrictClientAccessIpRelation) bool {
		return item.Ip == ip
	}) == 1
}
