package module

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
	"tmr-watch/conf/setting"
	"tmr-watch/http/handle/restful"
	"tmr-watch/models"
	"tmr-watch/pkg/logging"

	"github.com/Anderson-Lu/gofasion/gofasion"
	"github.com/gin-gonic/gin"
	"github.com/xormplus/xorm"
)

const (
	ClassDataSyncURl   = "group/class/sync"
	ClassDataDeleteURl = "group/class/sync"
)

func PostDataByName(c *gin.Context, fashion *gofasion.Fasion) (interface{}, error) {
	sqlnamestr := fashion.Get("name").ValueStr()
	s_params := make([]interface{}, 0)
	tx := restful.Engine.NewSession()
	defer tx.Close()
	err := tx.Begin()
	defer func() {
		switch {
		case err != nil:

			if tx != nil {
				tx.Rollback()
			}
		default:
			if tx != nil {
				err = tx.Commit()
			}
		}
		if tx != nil {
			tx.Close()
		}
	}()
	sql, p := restful.GetSqlByNameDBT(sqlnamestr, tx)
	if sql != "" {
		if fashion.HasKey("parammaps") {
			parammaps := fashion.Get("parammaps")
			logging.Info("PostDataByName ", sqlnamestr, parammaps.ValueStr())
			paramslist := strings.Split(p, ",")
			if len(paramslist) > 0 && p != "" {
				for _, value := range paramslist {
					if strings.ToLower(strings.Trim(value, " ")) == "jwt_username" {
						if tempv, exists := c.Get("jwt_username"); exists {
							s_params = append(s_params, tempv.(string))
						} else {
							s_params = append(s_params, "")
						}
					} else if strings.ToLower(strings.Trim(value, " ")) == "snowid" {
						ids, err := setting.SnowIds.NextId()
						if err != nil {
							ids = time.Now().UnixNano()
							logging.Info("create SnowIds err", err)
						}
						s_params = append(s_params, ids)
					} else {
						s_params = append(s_params, parammaps.Get(strings.Trim(value, " ")).ValueStr())
					}
				}
			}
		} else if fashion.HasKey("params") {
			params := fashion.Get("params").Array()
			logging.Info("PostDataByName ", sqlnamestr, params)
			for _, v_params := range params {
				s_params = append(s_params, v_params.ValueStr())
			}
		}
		queryData, err := ExecDataBySqlT(sql, s_params, tx)
		if err != nil {
			logging.Error("PostDataByName  err: ", err)
			//appG.Response(http.StatusOK, e.ERROR, err.Error())

			if (sqlnamestr == "copybarfeedremain" || sqlnamestr == "copyFtdry" || sqlnamestr == "copyPennsieve") &&
				strings.Contains(err.Error(), "Duplicate entry") {

				return nil, errors.New("同一栏舍,同一班次不可重复录入")
			} else if (sqlnamestr == "copybarmilk" || sqlnamestr == "copyBodyscore" || sqlnamestr == "copyDungsieve" || sqlnamestr == "copyDungscore") &&
				strings.Contains(err.Error(), "Duplicate entry") {
				return nil, errors.New("同一栏舍不可重复录入")
			} else {
				return nil, err
			}
		} else {
			return queryData, nil
		}
	}
	return nil, nil
}

func ParamsMarshal(keyWord string, fashion *gofasion.Fasion) (*models.ClassRequest, error) {
	params := fashion.Get("parammaps")
	classRequest := &models.ClassRequest{}
	if keyWord != "cow" {
		if err := json.Unmarshal([]byte(params.Json()), classRequest); err != nil {
			logging.Error("GroupCategorySync", "Unmarshal", err)
			return nil, err
		}
	} else {
		classCowRequest := &models.ClassCowRequest{}
		if err := json.Unmarshal([]byte(params.Json()), classCowRequest); err != nil {
			logging.Error("GroupCategorySync", "Unmarshal", err)
			return nil, err
		}
		classRequest.Enable = classCowRequest.Enable
		classRequest.PastureId = classCowRequest.PastureId
		classRequest.BigFeedClassId = classCowRequest.PastureId
		classRequest.BigFeedClassName = classCowRequest.ParentName
		classRequest.FcCode = classCowRequest.ClassCode
		classRequest.FcName = classCowRequest.ClassName
	}

	return classRequest, nil
}

func GroupCategorySync(keyWord string, fasion *gofasion.Fasion) error {
	classRequest, err := ParamsMarshal(keyWord, fasion)
	if err != nil {
		return err
	}
	parentId, _ := strconv.Atoi(classRequest.BigFeedClassId)
	pastureId, _ := strconv.Atoi(classRequest.PastureId)
	body := &models.CategoryRequest{
		KeyWord:    keyWord,
		PastureId:  int32(pastureId),
		ParentId:   int32(parentId),
		ParentName: classRequest.BigFeedClassName,
		Name:       classRequest.FcName,
		Number:     classRequest.FcCode,
		IsShow:     classRequest.Enable,
	}
	URL := fmt.Sprintf("%s/%s", GetGroupDomain(int64(pastureId)), ClassDataSyncURl)
	result, err := DoPost(URL, body)
	if err != nil {
		return err
	}

	response := &models.GroupCommonResponse{}
	if err = json.Unmarshal(result, response); err != nil {
		return err
	}
	if response.Code != http.StatusOK {
		return fmt.Errorf("msg: %s", response.Msg)
	}

	return nil
}

func GroupCategoryDelete(keyWord string, fashion *gofasion.Fasion) error {
	params := fashion.Get("parammaps")
	classRequest := &models.ClassDeleteRequest{}
	if err := json.Unmarshal([]byte(params.Json()), classRequest); err != nil {
		logging.Error("GroupCategorySync", "Unmarshal", err)
		return err
	}

	pastureId, _ := strconv.Atoi(classRequest.PastureId)
	dataId, _ := strconv.Atoi(classRequest.Id)
	body := &models.GroupCategoryDeleteRequest{
		KeyWord:   keyWord,
		PastureId: int32(pastureId),
		DataId:    int32(dataId),
	}
	URL := fmt.Sprintf("%s/%s", GetGroupDomain(int64(pastureId)), ClassDataDeleteURl)
	result, err := DoPost(URL, body)
	if err != nil {
		return err
	}

	response := &models.GroupCommonResponse{}
	if err = json.Unmarshal(result, response); err != nil {
		return err
	}
	if response.Code != http.StatusOK {
		return fmt.Errorf("msg: %s", response.Msg)
	}
	return nil
}

func GetGroupDomain(pastureId int64) string {
	res := &models.SysOpt{}
	if _, err := restful.Engine.Table(new(models.SysOpt).TableName()).
		Where("pastureid = ?", pastureId).And("inforname = ?", "domain").Get(res); err != nil {
		logging.Error("GetGroupDomain", err)
		return ""
	}
	return res.InforValue
}

func ExecDataBySqlT(sqlstr string, params []interface{}, tx *xorm.Session) (interface{}, error) {
	queryData, err := restful.ExecQueryT(sqlstr, params, tx)
	return queryData, err
}

type GroupClient struct {
	Detail     *models.Pasture
	authClient *http.Client
}

func NewGroupClient(detail *models.Pasture) *GroupClient {
	return &GroupClient{
		Detail: detail,
		authClient: &http.Client{
			Timeout: time.Duration(5) * time.Second,
		},
	}
}

func doRequest(req *http.Request) ([]byte, error) {
	groupClient := NewGroupClient(nil)
	resp, err := groupClient.authClient.Do(req)
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		if len(b) > 0 {
			return nil, fmt.Errorf("err:%v,body:%s", err, string(b))
		} else {
			return nil, fmt.Errorf("err:%v", err)
		}
	}
	return b, nil
}

func DoGet(url string) ([]byte, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Content-Type", "application/json")
	return doRequest(req)
}

func DoPost(url string, body interface{}) ([]byte, error) {
	b, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(b))
	if err != nil {
		return nil, err
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Content-Type", "application/json")
	return doRequest(req)
}