package repository

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"gin-vue-admin/common"
	"gin-vue-admin/models"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// QueryChainCodeByPhone 查询用户使用的是哪个医院的数据
func QueryChainCodeByPhone(phone string) (interface{}, error) {

	db, err := common.NewAccountConn()
	if err != nil {
		return nil, err
	}

	// 查询医院是否存在
	var chainCode string
	err = db.QueryRow(`select default_chain_code from employee_wx
	where employee_phone = ?`, phone).Scan(&chainCode)
	if err != nil {
		return nil, err
	}

	if chainCode == "" {
		return nil, errors.New("查不到这个用户")
	}

	return chainCode, nil
}

// QueryRoleAuthorityTableByDB 查询表是否存在
func QueryRoleAuthorityTableByDB(db *sql.DB) (isExist string, err error) {

	isExist = ""
	err = db.QueryRow(`SELECT table_name FROM information_schema.TABLES 
	WHERE table_name = 'doctor_role_permission'`).Scan(&isExist)

	return isExist, err
}

// QueryChainCodeAndLocalIDByPhone 查询用户信息
func QueryChainCodeAndLocalIDByPhone(phone string) (string, int, error) {

	db, err := common.NewAccountConn()
	if err != nil {
		return "", 0, err
	}

	// 查询医院是否存在
	var chainCode string
	var employeeLocalID int
	err = db.QueryRow(`select default_chain_code, employee_local_id from hos_database.employee_wx
	where employee_phone = ?`, phone).Scan(&chainCode, &employeeLocalID)
	switch {
	case err == sql.ErrNoRows:
		return "", 0, errors.New("没有这个用户")
	case err != nil:
		return "", 0, err
	}

	return chainCode, employeeLocalID, nil
}

// 查询医院本地id
func QueryHospitalLocalIDByEmployeeLocalID(db *sql.DB, employeeLocalID int) (int, error) {

	var hospitalID int
	err := db.QueryRow(`select sys_hospital_id from con_employee where id = ?`, employeeLocalID).Scan(&hospitalID)
	return hospitalID, err
}

func QueryHospitalCodeByEmployeeLocalID(db *sql.DB, hospitalLocalID int) (string, error) {

	var hospitalCode string
	err := db.QueryRow(`select hospital_code from sys_hospital where id = ?`, hospitalLocalID).Scan(&hospitalCode)
	return hospitalCode, err
}

// QueryWxModuleInfo 查询微信小程序模块信息
func QueryWxModuleInfo() ([]models.WxDoctorModule, error) {

	db, err := common.NewAccountConn()
	if err != nil {
		return nil, err
	}

	response := make([]models.WxDoctorModule, 0)

	rows, err := db.Query(`select id, _name, icon from wx_doctor_module`)
	if err != nil {
		return nil, err
	}

	for rows.Next() {
		var t models.WxDoctorModule
		err = rows.Scan(&t.ID, &t.Name, &t.Icon)
		if err != nil {
			return nil, err
		}
		response = append(response, t)
	}

	return response, nil
}

// GetHospitalID 获取医院本地ID
func GetHospitalID(db *sql.DB, employeeLocalID int) (int64, error) {
	var hospitalID int64
	err := db.QueryRow(`select sys_hospital_id from con_employee where id = ?`, employeeLocalID).Scan(&hospitalID)
	return hospitalID, err
}

// GetCodeByTable 获取 code 编号
func GetCodeByTable(db *sql.DB, hospitalID int64, tableName, tag string) (string, error) {

	var code string

	err := db.QueryRow("select _code from "+tableName+" where delflag = 0 and sys_hospital_id = ? order by id desc limit 1", hospitalID).Scan(&code)
	if tag != "P" {
		if tableName == common.EmployeeTable {
			switch {
			case err == sql.ErrNoRows:
				return tag + "000001", nil
			case err != nil:
				return "", err
			}
			codeLength := len(code)
			if codeLength != 8 {
				return tag + "000001", nil
			}
			numstr := code[2:]
			num, err := strconv.ParseInt(numstr, 10, 0)
			if err != nil {
				return tag + "000001", nil
			}
			code = fmt.Sprintf("%s%0"+fmt.Sprintf("%d", len(numstr))+"d", tag, num+1)
		} else {
			preCode := tag + time.Now().Format("20060102")
			switch {
			case err == sql.ErrNoRows:
				return preCode + "0001", nil
			case err != nil:
				return "", err
			}

			if len(code) < 9 {
				return preCode + "0001", nil
			}

			if code[2:10] == preCode[2:] {
				codeIndex, err := strconv.ParseInt(code[10:], 10, 0)
				if err != nil {
					return "", err
				}
				codeIndex++
				code = fmt.Sprintf("%s%04d", preCode, codeIndex)
			} else {
				code = preCode + "0001"
			}
		}

	} else {
		if tableName == common.PetTable {
			switch {
			case err == sql.ErrNoRows:
				return tag + "000001", nil
			case err != nil:
				return "", err
			}
			codeLength := len(code)
			index := 0
			for i := codeLength; i > 0; i-- {
				_, err := strconv.Atoi(code[i-1 : i])
				if err != nil {
					index = i
					break
				}
			}
			pre := code[:index]
			numstr := code[index:]
			num, err := strconv.ParseInt(numstr, 10, 0)
			if err != nil {
				return tag + "000001", nil
			}
			code = fmt.Sprintf("%s%0"+fmt.Sprintf("%d", len(numstr))+"d", pre, num+1)
		} else {
			switch {
			case err == sql.ErrNoRows:
				return tag + "000000001", nil
			case err != nil:
				return "", err
			}
			codeLength := len(code)
			index := 0
			for i := codeLength; i > 0; i-- {
				_, err := strconv.Atoi(code[i-1 : i])
				if err != nil {
					index = i
					break
				}
			}
			pre := code[:index]
			numstr := code[index:]
			num, err := strconv.ParseInt(numstr, 10, 0)
			if err != nil {
				return tag + "000000001", nil
			}
			code = fmt.Sprintf("%s%0"+fmt.Sprintf("%d", len(numstr))+"d", pre, num+1)
		}
	}
	return code, nil
}

func ISNewStock(chainCode string) (int, error) {

	db, err := common.NewAccountConn()
	if err != nil {
		return 0, err
	}

	var is int
	err = db.QueryRow(`select is_new_stock from hos_database.chain_main
	where chain_code = ?`, chainCode).Scan(&is)
	if err != nil {
		return is, err
	}
	return is, err
}

//  @author: yaoyuliang
//  @date: 2022-05-20 15:41:00
//  @Description: 判断是否商品
//
func CheckIsGeneralHospital(hospitalLocalId int, chainCode string, db *sql.DB) (bool, error) {

	// 1.主院直接返回全部
	// 2.分院通过医院设置类型判断是否显示全部

	var (
		checkCode    string
		createTime   string
		hospitalCode string
	)

	err := db.QueryRow("select hospital_code from sys_hospital where id = ? ", hospitalLocalId).Scan(&hospitalCode)
	if err != nil {
		return false, err
	}

	// 主院创建时间
	err = db.QueryRow("select hospital_code,createtime from sys_hospital where delflag =0  limit 1 ").Scan(&checkCode, &createTime)
	if err != nil {
		return false, err
	}

	// 是主院返回全部
	if checkCode == hospitalCode {
		return true, nil
	}

	//是分院 查看是不是商品互通类型医院
	sign, err := GetSign(chainCode, hospitalCode)
	if err != nil {
		return false, err
	}

	goodCommon, err := GatewayHttpRequestReturnUnmarshal(http.MethodGet, "https://gateway.pet-dbc.cn/gateway/hospital/info/check_is_good_common", sign, nil, "")
	if err != nil {
		return false, err
	}

	//商品不互通医院不显示全部
	if goodCommon["data"].(map[string]interface{})["is_good_common"] == 1.0 {
		return false, err
	}

	return true, nil

}

func GatewayHttpRequestReturnUnmarshal(method, url string, sign map[string]string, param interface{}, bodyInfo string) (map[string]interface{}, error) {

	// 封装http的请求
	client := &http.Client{}

	var (
		info io.Reader
		body []byte
	)

	tempResult := make(map[string]interface{}, 0)

	if param != nil {
		b, err := json.Marshal(param)
		if err != nil {
			return nil, err
		}
		info = bytes.NewReader(b)
	}

	if bodyInfo != "" {
		info = strings.NewReader(bodyInfo)
	}

	req, err := http.NewRequest(method, url, info)
	if err != nil {
		return tempResult, err
	}

	req.Header.Set("Content-Type", "application/json")
	if sign != nil && len(sign) > 0 {
		for k, v := range sign {
			req.Header.Set(k, v)
		}
	}

	resp, err := client.Do(req)
	if err != nil {
		return tempResult, err
	}

	if resp != nil {
		body, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return tempResult, err
		}
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return tempResult, errors.New("unknown mistake")
	}

	err = json.Unmarshal(body, &tempResult)
	if err != nil {
		return tempResult, err
	}

	return tempResult, err

}

func GetSign(chainCode, registerCode string) (map[string]string, error) {

	sign, err := AesEncrypt([]byte(chainCode+"|"+registerCode), []byte("dbcaespassword01"))
	if err != nil {
		return nil, errors.New("获取sign失败")
	}

	signData := make(map[string]string)
	signData["sign"] = sign

	return signData, err
}

//Aes 对称加密
func AesEncrypt(origData, key []byte) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	origData = PKCS7Padding(origData, blockSize)
	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
	crypted := make([]byte, len(origData))
	blockMode.CryptBlocks(crypted, origData)
	result := base64.StdEncoding.EncodeToString(crypted)
	return result, nil
}

func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func QueryArray(db *sql.DB, q string, args ...interface{}) ([]map[string]string, error) {

	rows, err := db.Query(q, args...)
	if err != nil {
		return nil, err
	}

	// Get column names
	columns, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	values := make([]sql.RawBytes, len(columns))

	scanArgs := make([]interface{}, len(values))
	for i := range values {
		scanArgs[i] = &values[i]
	}

	// 最终要返回的data
	data := make([]map[string]string, 0)
	// Fetch rows
	for rows.Next() {
		err = rows.Scan(scanArgs...)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}

		//每行数据
		row := make(map[string]string)
		for k, v := range values {
			key := columns[k]
			row[key] = string(v)
		}
		//放入结果集
		data = append(data, row)
	}

	return data, nil
}

func GetRemind(db *sql.DB, hospitalId int) (interface{}, error) {
	sqlStr := "select id, `_key` as 'key', _name as 'name', `_value` as 'value' from sys_config where sys_hospital_id=? "

	d, err := QueryArrays(db, sqlStr, hospitalId)
	if err != nil {
		return nil, err
	}
	return d, nil
}