package utils

import (
	"errors"
	"spaceofcheng/services/models/model"
	"strings"
)

// 系统内置数据种类
const (
	DATATYPE_USER   = "user"
	DATATYPE_CASE   = "case"
	DATATYPE_COURSE = "course"
	DATATYPE_COUPON = "coupon"
	DATATYPE_CARD   = "card"
)

// DataAuthEngine 鉴权数据
type DataAuthEngine struct {
	ctx *Context
}

// NewAuthEngine 生成新实例
func NewAuthEngine(ctx *Context) *DataAuthEngine {
	return &DataAuthEngine{ctx: ctx}
}

// CheckCase 校验案场数据权限
func (t *DataAuthEngine) CheckCase(caseID string) error {
	cases := t.ctx.Get("cases")
	if cases == nil {
		return errors.New("请授权用户案场权限")
	}

	found := false
	userCases := cases.([]model.SysUserCase)

	for _, cs := range userCases {
		if caseID == cs.CaseId {
			found = true
		}
	}

	if !found {
		return errors.New("用户无该案场数据权限")
	}

	return nil
}

// AuthFilter 按权限过滤
func (t *DataAuthEngine) AuthFilter(targ interface{}, sql string, params ...interface{}) error {
	if t.ctx == nil {
		return errors.New("未指定上下文环境")
	}

	// 用户所属案场
	casesRaw := t.ctx.Get("cases")
	if casesRaw == nil {
		return errors.New("用户无权限操作该数据")
	}
	cases := casesRaw.([]model.SysUserCase)
	csIDs := make([]string, 0)
	for _, cs := range cases {
		csIDs = append(csIDs, cs.CaseId)
	}

	newSQL := "select * from (" + sql + ") where case_id in ('" + strings.Join(csIDs, "','") + "')"
	if err := t.ctx.DB.SQL(newSQL, params...).Find(targ); err != nil {
		LogError("按权限查询数据失败: " + err.Error())
		return errors.New("数据查询失败")
	}

	return nil
}

// HasUserPermission 是否有人员权限
func (t *DataAuthEngine) HasUserPermission(userID, borrower string, caseID ...string) error {
	// 1、先判断组织是否相同
	userOrg, err := t.getOrgOfData(userID, DATATYPE_USER)
	if err != nil {
		LogError("查询用户(" + userID + ") 所属组织失败: " + err.Error())
		return errors.New("查询用户相关信息失败")
	}

	borwOrg, err := t.getOrgOfData(borrower, DATATYPE_USER)
	if err != nil {
		LogError("查询用户(" + borrower + ") 所属组织失败: " + err.Error())
		return errors.New("查询用户相关信息失败")
	}

	if userOrg != borwOrg {
		return errors.New("人员不存在或无权浏览")
	}

	// 2、再判断是否案场相同
	sameCases, err := t.getSameCase(userID, borrower)
	if err != nil {
		return errors.New("用户没有相同案场授权")
	}

	// 3、是否指定了案场
	if len(caseID) > 0 {
		if StrSliceIndexOf(sameCases, caseID[0]) < 0 {
			return errors.New("用户没有当前案场权限")
		}
	}

	return nil
}

func (t *DataAuthEngine) getOrgOfData(dataID, dataType string) (string, error) {
	org := make(map[string]interface{})

	switch dataType {
	// 用户
	case DATATYPE_USER:
		if _, err := t.ctx.DB.SQL("select org_id from sys_user where user_id = ?", dataID).Get(&org); err != nil {
			return "", err
		}

		orgID := org["org_id"].(string)
		return orgID, nil

		// 案场
	case DATATYPE_CASE:
		if _, err := t.ctx.DB.SQL("select org_id from sys_case where case_id = ?", dataID).Get(&org); err != nil {
			return "", err
		}

		orgID := org["org_id"].(string)
		return orgID, nil
	default:
		return "", nil
	}
}

func (t *DataAuthEngine) getSameCase(user1, user2 string) ([]string, error) {
	sql := `
		SELECT t.case_id
		FROM
			sys_user_case t
		JOIN sys_user_case s ON t.user_id = ?
		AND s.user_id = ?
		AND t.case_id = s.case_id	
	`
	res, err := t.ctx.DB.Query(sql, user1, user2)
	if err != nil {
		LogError("查询用户相同案场失败: " + err.Error())
		return nil, err
	}

	if res == nil || len(res) == 0 {
		return nil, errors.New("用户没有相同案场授权")
	}

	csIDs := make([]string, 0)
	for _, cs := range res {
		csIDs = append(csIDs, string(cs["case_id"]))
	}

	return csIDs, nil
}
