package tools

import (
	"encoding/json"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"io"
	"qfw/util"
	//"fmt"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	mu "mfw/util"
	"net"
	"os"
	"runtime"
	"strconv"
	"strings"
	u "util"
)

var DbInfo map[string][]string //账号密码信息
var AllTaskFinish = false
var ControlTaskRun bool //是否控制招标分类-->业主分类流程
var ControlLastTaskId string
var Udpclient mu.UdpClient //udp对象
type UdpNode struct {
	Data      []byte
	Addr      *net.UDPAddr
	Timestamp int64
	Retry     int
}

var (
	ExtractAddr  string
	ExtractPort  int
	ExtractStype string
	Extract      map[string]interface{}
)

var (
	Config      map[string]interface{}
	MgoClass    *u.MongodbSim //规则库
	MgoClassOld *u.MongodbSim //规则库,ai 第二套时，需要使用qfw 老的数据库连接，更新bidding_processing_ids
	MgoDcs      *u.MongodbSim //分布式保存库
	NoAutoRun   int
	Fields      []string
	ossClient   *oss.Client
	BucketName  string
	IsOss       bool
)

// 定时任务
var (
	IsStart      bool   //是否执行
	IdCollSid    string //ocr_flie_over id
	TimeTaskid   string //任务id
	NextNodeAddr string //项目预测地址
	NextNodePort int    //项目预测udp端口
)

type JSON struct {
	Status bool        `json:"status"`
	Msg    string      `json:"msg"`
	Data   interface{} `json:"data"`
}

var COLL_RULE = "rc_rule"
var COLL_TASK = "rc_task"
var COLL_CLASS = "rc_class"

//type Merge struct {
//	Coll string
//	Db   string
//	MGO  MongodbSim
//}

//var MergeMap map[string]*Merge

func Try(fun func()) {
	defer Catch()
	fun()
}

func init() {
	ReadConfig(&Config)
	DbInfo = map[string][]string{}
	for t, tmp := range Config["dbinfo"].(map[string]interface{}) { //mgo账号密码信息
		tmpMap := tmp.(map[string]interface{})
		username := tmpMap["username"].(string)
		password := tmpMap["password"].(string)
		DbInfo[t] = []string{username, password}
	}

	ControlTaskRun = Config["controltaskrun"].(bool)
	ControlLastTaskId = Config["controllastaskid"].(string)
	fields := Config["fields"].(string)
	Fields = strings.Split(fields, ",")
	MgoClass = &u.MongodbSim{
		MongodbAddr: Config["mgoaddr"].(string),
		Size:        IntAll(Config["mgosize"]),
		DbName:      Config["dbname"].(string),
	}
	if Config["isbidding"].(bool) { //目前分类规则表在招标bidding库需要账号密码
		MgoClass.UserName = DbInfo["bidding"][0]
		MgoClass.Password = DbInfo["bidding"][1]
	}
	MgoClass.InitPool()
	// qfw 老数据库
	if util.ObjToString(Config["dbname_old"]) != "" {
		MgoClassOld = &u.MongodbSim{
			MongodbAddr: Config["mgoaddr"].(string),
			Size:        IntAll(Config["mgosize"]),
			DbName:      Config["dbname_old"].(string),
		}
		if Config["isbidding"].(bool) { //目前分类规则表在招标bidding库需要账号密码
			MgoClassOld.UserName = DbInfo["bidding"][0]
			MgoClassOld.Password = DbInfo["bidding"][1]
		}
		MgoClassOld.InitPool()
	}

	MgoDcs = &u.MongodbSim{ //分布式目前只在跑历史数据时应用，不连招标库不需要配账号密码
		MongodbAddr: Config["mgoaddr"].(string),
		Size:        IntAll(Config["mgosize"]),
		DbName:      Config["dbname_dis"].(string),
		// UserName:    UserName,
		// Password:    PassWord,
	}
	MgoDcs.InitPool()

	NoAutoRun = IntAllDef(Config["noautorun"], 1)

	Extract, _ = Config["extract"].(map[string]interface{})
	if Extract != nil {
		ExtractAddr = Extract["addr"].(string)
		ExtractPort = IntAll(Extract["port"])
		ExtractStype = Extract["stype"].(string)
	}
	//定时任务信息
	timeTaskInfo := Config["timetask"].(map[string]interface{})
	IsStart = timeTaskInfo["istart"].(bool)
	TimeTaskid = timeTaskInfo["taskid"].(string)
	IdCollSid = timeTaskInfo["idcollsid"].(string)
	NextNodeAddr = timeTaskInfo["nextnodeaddr"].(string)
	NextNodePort = IntAll(timeTaskInfo["nextnodeport"])
	/*
		MergeMap = make(map[string]*Merge)
		for k, v := range Config {
			merge := &Merge{}
			if m, ok := v.(map[string]interface{}); ok {
				addr, _ := m["mgoaddr"].(string)
				db, _ := m["db"].(string)
				coll, _ := m["coll"].(string)
				if addr != "" && db != "" && coll != "" {
					log.Println(addr, coll, db)
					m := MongodbSim{
						MongodbAddr: addr,
						Size:        10,
						DbName:      db,
					}
					m.InitPool()

					merge.MGO = m
					merge.Coll = coll
					merge.Db = db

					MergeMap[k] = merge
				}
			}
		}
	*/

	//初始化oss
	InitOss()
}

// InitOss 初始化OSS
func InitOss() {
	IsOss = Config["is_oss"].(bool)
	if IsOss {
		ossConf, ok := Config["oss"].(map[string]interface{})
		if ok {
			client, err := oss.New(util.ObjToString(ossConf["endpoint"]), util.ObjToString(ossConf["access_key"]), util.ObjToString(ossConf["access_secret"]))
			if err != nil {
				fmt.Println("Error:", err)
				os.Exit(-1)
			}
			BucketName = util.ObjToString(ossConf["bucket_name"])
			ossClient = client
		}
	}
}

// OssGetObject 获取oss 数据，objectName 默认标讯id,ossBucketName 默认 jy-datadetail 获取详情detail
func OssGetObject(objectName, ossBucketName string) string {
	util.Catch()
	// 获取存储空间。
	bucket, err := ossClient.Bucket(ossBucketName)
	if err != nil {
		fmt.Println("Error:", err)
		return ""
	}

	// 下载文件到流。
	body, err := bucket.GetObject(objectName)
	if err != nil {
		fmt.Println("Error:", err)
		return ""
	}
	defer body.Close()
	data, err := io.ReadAll(body)
	if err != nil {
		fmt.Println("Error:", err)
		return ""
	}
	return string(data)
}

func Catch() {
	if r := recover(); r != nil {
		log.Println(r)
		for skip := 0; ; skip++ {
			_, file, line, ok := runtime.Caller(skip)
			if !ok {
				break
			}
			go log.Printf("%v,%v\n", file, line)
		}
	}
}

func CheckError(err error) {
	if err != nil {
		go log.Println(err.Error())
	}
}

func IntAll(num interface{}) int {
	return IntAllDef(num, 0)
}

func IntAllDef(num interface{}, defaultNum int) int {
	if i, ok := num.(int); ok {
		return int(i)
	} else if i0, ok0 := num.(int32); ok0 {
		return int(i0)
	} else if i1, ok1 := num.(float64); ok1 {
		return int(i1)
	} else if i2, ok2 := num.(int64); ok2 {
		return int(i2)
	} else if i3, ok3 := num.(float32); ok3 {
		return int(i3)
	} else if i4, ok4 := num.(string); ok4 {
		in, _ := strconv.Atoi(i4)
		return int(in)
	} else if i5, ok5 := num.(int16); ok5 {
		return int(i5)
	} else if i6, ok6 := num.(int8); ok6 {
		return int(i6)
	} else {
		return defaultNum
	}
}
func Int64All(num interface{}) int64 {
	if i, ok := num.(int64); ok {
		return int64(i)
	} else if i0, ok0 := num.(int32); ok0 {
		return int64(i0)
	} else if i1, ok1 := num.(float64); ok1 {
		return int64(i1)
	} else if i2, ok2 := num.(int); ok2 {
		return int64(i2)
	} else if i3, ok3 := num.(float32); ok3 {
		return int64(i3)
	} else if i4, ok4 := num.(string); ok4 {
		i64, _ := strconv.ParseInt(i4, 10, 64)
		//in, _ := strconv.Atoi(i4)
		return i64
	} else if i5, ok5 := num.(int16); ok5 {
		return int64(i5)
	} else if i6, ok6 := num.(int8); ok6 {
		return int64(i6)
	} else if i7, ok7 := num.(*big.Int); ok7 {
		in, _ := strconv.ParseInt(fmt.Sprint(i7), 10, 64)
		return int64(in)
	} else if i8, ok8 := num.(*big.Float); ok8 {
		in, _ := strconv.ParseInt(fmt.Sprint(i8), 10, 64)
		return int64(in)
	} else {
		return 0
	}
}

// 读取配置文件
func ReadConfig(config ...interface{}) {
	var r *os.File
	filepath := "./config.json"
	if len(config) > 1 {
		filepath, _ = config[0].(string)
	}
	r, _ = os.Open(filepath)
	defer r.Close()
	bs, _ := ioutil.ReadAll(r)
	json.Unmarshal(bs, config[0])
}

// func ObjToString(old interface{}) string {
// 	defer func() {
// 		if r := recover(); r != nil {
// 		}
// 	}()
// 	if nil == old {
// 		return ""
// 	} else if old == bson.Undefined {
// 		return ""
// 	} else {
// 		return old.(string)
// 	}
// }

// 对象数组转成string数组
func ObjArrToStringArr(old []interface{}) []string {
	defer Catch()
	if old != nil {
		new := make([]string, len(old))
		for i, v := range old {
			new[i] = v.(string)
		}
		return new
	} else {
		return nil
	}
}

//根据bsonID转string
// func BsonIdToSId(uid interface{}) string {
// 	if u, ok := uid.(string); ok {
// 		return u
// 	} else {
// 		return fmt.Sprintf("%x", string(uid.(bson.ObjectId)))
// 	}
// }
