package common

import (
	"fmt"
	"gorm.io/gorm"
	"math/rand"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// Operation type 操作类型
const (
	OperationDefault          = iota
	OperationLogin            //登录
	OperationLogout           //注销
	OperationCreate           //新增
	OperationUpdate           //修改
	OperationRemove           //删除
	OperationImport           //导入导出
	OperationLightStrategy    //开关灯控策略
	OperationOrderCreate      //工单发起
	OperationOrderChange      //工单转派
	OperationOrderHandle      //工单处理
	OperationProgramPublish   //节目发布待审核
	OperationProgramResult    //节目处理结果
	OperationStrategyRelation //策略关联
	OperationControl          //操作
	OperationAlarmHandle      //告警处理

	OperationSuccess = 0
	OperationFail    = 1
)

const (
	ModuleTypeDefault        = iota //操作记录模块
	ModuleTypeDevice                //设备台账管理
	ModuleTypeInfoBar               //信息发布系统
	ModuleTypeOrder                 //工单运维
	ModuleTypeNotification          //通知公告
	ModuleTypeLightStrategy         //照明策略
	ModuleTypeLighting              //智慧照明系统-智能照明
	ModuleTypeSystem                //系统管理
	ModuleTypeAlarm                 //告警管理
	ModuleTypeOperation             //运营分析
	ModuleTypeRecord                //记录处理
	ModuleTypeWisdomLighting        //智能感应照明系统-灯随车走照明控制
)

// deviceType 设备类型 1** 交通 2** 农业
const (
	DeviceTypeDefault        = 0   //--
	DeviceTypeCamera         = 100 //摄像头
	DeviceTypeLightControl   = 101 //灯控
	DeviceTypeInfoBoard      = 102 //信息屏
	DeviceTypeSwitchBox      = 103 //配电箱
	DeviceTypeGateway        = 104 //网关
	DeviceTypeOptoSensor     = 105 // 环境监测
	DeviceTypeZigbee         = 106 //ZigBee
	DeviceTypeAlarmTerminal  = 107 //一键告警终端
	DeviceTypeAlarmServer    = 108 //一键告警服务端
	DeviceTypeBridgeSensor   = 109 //桥梁传感器
	DeviceTypeBridge         = 110 //桥梁
	DeviceTypeIPBroadcast    = 111 //ip音柱
	DeviceTypeManholeCover   = 112 //井盖
	DeviceTypeGarbage        = 113 //垃圾桶
	DeviceTypeLampPoleGroup  = 114 //灯杆分组
	DeviceTypeLampPole       = 115 //灯杆
	DeviceTypeCaptureUnit    = 116 //抓拍单元
	DeviceTypePoint          = 117 //卡口
	DeviceTypeGarbageGroup   = 118 //垃圾桶分组
	DeviceTypeLightStrategy  = 119 //灯控策略
	DeviceTypeOnDemandGroup  = 120 //灯随车走分组
	DeviceTypeOnDemandSensor = 121 //灯随车走传感器
	DeviceTypeTransformer    = 122 //变压器
)

var mLocation *time.Location

func init() {
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		mLocation = time.FixedZone("CST", 8*3600)
	} else {
		mLocation = loc
	}
}

func GetDeviceObject(id int, name string) string {
	return strconv.Itoa(id) + "(" + name + ")"
}

func StringToInt(id string) int {
	if id != "" {
		id, err := strconv.Atoi(id)
		if err == nil {
			return id
		}
	}
	return -1
}

func RandomString(n int) string {
	var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	rand.Seed(time.Now().Unix())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func RandomString2(n int) string {
	//var letters = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
	var letters = []rune("123456789")
	rand.Seed(time.Now().Unix())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func StringToInt64Array(str string) []int64 {
	tmp := strings.Split(str, ",")
	var result []int64
	for _, t := range tmp {
		i, _ := strconv.ParseInt(t, 10, 64)
		result = append(result, i)
	}
	return result
}

func StringToIntArray(str string) []int {
	tmp := strings.Split(str, ",")
	var result []int
	for _, t := range tmp {
		i, _ := strconv.Atoi(t)
		result = append(result, i)
	}
	return result
}

func MlParseTime(strTime string) (time.Time, error) {
	if strings.Contains(strTime, ".") {
		return time.ParseInLocation("2006-01-02 15:04:05.000", strTime, mLocation)
	}
	return time.ParseInLocation("2006-01-02 15:04:05", strTime, mLocation)
}

func IsAdmin(roleId int64) bool {
	return roleId == 1
}

// TableModelAuto 给表命名字
type TableModelAuto struct {
	Model   interface{}
	Comment string
}

// MultimediaEfficacyTime ip音柱效验时间是否在当前时间之前
func MultimediaEfficacyTime(stime Time, etime Time, time2 string) bool {
	stimeStr := stime.String()
	etimeStr := etime.String()
	if stimeStr == "" || etimeStr == "" || time2 == "" {
		return true
	}
	currDate := time.Now().Format("2006-01-02")

	kstime := currDate + time2
	nowTime, _ := time.Parse("2006-01-02 15:04:05", kstime)
	time3 := time.Now()
	if etimeStr == stimeStr && currDate == etimeStr && time3.Before(nowTime) {
		return false
	}
	return true
}

// Paginate 翻页
func Paginate(page int, size int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		page := page
		if page == 0 {
			page = 1
		}
		pageSize := size
		switch {
		case pageSize > 100:
			pageSize = 100
		case pageSize <= 0:
			pageSize = 10
		}
		offset := (page - 1) * pageSize
		return db.Offset(offset).Limit(pageSize)
	}
}

var timeTemplates = []string{
	"2006-01-02 15:04:05", //常规类型
	"2006/01/02 15:04:05",
	"2006-01-02",
	"2006/01/02",
	"15:04:05",
}

/* 时间格式字符串转换 */
func TimeStringToGoTime(tm string) time.Time {
	for i := range timeTemplates {
		t, err := time.ParseInLocation(timeTemplates[i], tm, time.Local)
		if nil == err && !t.IsZero() {
			return t
		}
	}
	return time.Time{}
}

// GetTimeDays 时间区间的所有天数
func GetTimeDays(start_time, stop_time string) []string {
	star := []rune(start_time)
	end := []rune(stop_time)
	tm1, _ := time.Parse("2006-01-02", string(star[:10]))
	tm2, _ := time.Parse("2006-01-02", string(end[:10]))
	//fmt.Printf("star = %v \n", string(star[:10]))
	sInt := tm1.Unix()
	eInt := tm2.Unix()
	var args []string
	for {
		sInt += 86400
		st := time.Unix(sInt, 0).Format("2006-01-02")
		args = append(args, st)
		if sInt > eInt {
			break
		}
	}
	var days []string
	for i := 0; i < len(args); i++ {
		parse, _ := time.Parse("2006-01-02", string(star[:10]))
		date := parse.AddDate(0, 0, i).Format("2006-01-02")
		days = append(days, date)
	}
	return Reverse(days)
}

// GetTimeMonths 时间区间的所有月份
func GetTimeMonths(start_time, stop_time string) []string {
	star := []rune(start_time)
	end := []rune(stop_time)
	var months []string
	i := 0
	for {
		parse, _ := time.Parse("2006-01", string(star[:7]))
		endStr, _ := time.Parse("2006-01", string(end[:7]))
		month := parse.AddDate(0, i, 0).Format("2006-01")
		month = month + "-01"
		months = append(months, month)
		if month == endStr.Format("2006-01")+"-01" || i > 24 {
			break
		}
		i++
	}
	return Reverse(months)
}

// Decimal float64 保留2位小数
func Decimal(value float64) float64 {
	value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
	return value
}

// Reverse 反转数组
func Reverse(s []string) []string {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
	return s
}

func InIntArr(target int, str_array []int) bool {
	for _, element := range str_array {
		if target == element {
			return true
		}
	}
	return false
}

func ACopyToB(a interface{}, b interface{}) {
	vVal := reflect.ValueOf(a).Elem() //获取reflect.Type类型
	bVal := reflect.ValueOf(b).Elem() //获取reflect.Type类型
	vTypeOfT := vVal.Type()
	for i := 0; i < vVal.NumField(); i++ {
		// 在要修改的结构体中查询有数据结构体中相同属性的字段，有则修改其值
		name := vTypeOfT.Field(i).Name
		if ok := bVal.FieldByName(name).IsValid(); ok {
			bVal.FieldByName(name).Set(reflect.ValueOf(vVal.Field(i).Interface()))
		}
	}
}

// 例如，若想将值 50 从区间 [0, 100] 映射到区间 [-1, 1] 中，则可以调用该函数如下：
// mappedValue :=  common.MapRange(50, 0, 100, -1, 1)
func MapRange(value, fromLow, fromHigh, toLow, toHigh float64) float64 {
	// Check for invalid input values
	if value < fromLow || value > fromHigh || fromLow == fromHigh || toLow == toHigh {
		return -1
	}

	// Calculate the ratio of the input range
	ratio := (value - fromLow) / (fromHigh - fromLow)

	// Scale the ratio to the output range and return the result
	return (ratio * (toHigh - toLow)) + toLow
}
