package yinbaoapi

import (
	"bytes"
	"encoding/json"
	"fmt"
	"math/rand"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"regexp"
	"strings"

	"git.rosy.net.cn/baseapi"
	"git.rosy.net.cn/baseapi/platformapi"
	"git.rosy.net.cn/baseapi/utils"
)

const (
	pageUrl                = "https://beta27.pospal.cn"
	MainStoreVendorOrgCode = "3933189"
	letterBytes            = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
)

var (
	regexpSkuID = regexp.MustCompile(`<tr data="(.*?)"`)
)

func (a *API) AccessStorePage(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
	fullURL := utils.GenerateGetURL(pageUrl, action, nil)
	// result, _ := json.MarshalIndent(bizParams, "", " ")
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			request, _ := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.Map2URLValues(bizParams).Encode()))
			request.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
			a.FillRequestCookies(request)
			return request
		},
		a.config,
		func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
			if jsonResult1 == nil {
				return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
			}
			if err == nil {
				if jsonResult1["successed"] != nil {
					if !jsonResult1["successed"].(bool) {
						errLevel = platformapi.ErrLevelGeneralFail
						err = utils.NewErrorCode(jsonResult1["msg"].(string), "-1", 0)
					}
				} else {
					errLevel = platformapi.ErrLevelGeneralFail
					if strings.Contains(jsonResult1["fakeData"].(string), "登录") {
						err = utils.NewErrorCode("银豹Cookie可能失效了！", "-1", 0)
					}
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}

func RandStringBytes(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b)
}

func getBoundary() (boundary string) {
	boundary = "----WebKitFormBoundary"
	boundary += RandStringBytes(16)
	return boundary
}

func (a *API) AccessStorePage2(action string, userID, productID string, data []byte, fileName string) (retVal map[string]interface{}, err error) {
	// 实例化multipart
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	writer.SetBoundary(getBoundary())
	// 创建multipart 文件字段
	h := make(textproto.MIMEHeader)
	h.Set("Content-Disposition",
		fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
			"file", fileName))
	h.Set("Content-Type", "image/jpeg")
	part, _ := writer.CreatePart(h)
	// part, _ := writer.CreateFormFile("file", "4ff17b24fdccfc37fd0847469a8039e9.jpg")
	// 写入文件数据到multipart，和读取本地文件方法的唯一区别
	_, err = part.Write(data)
	//将额外参数也写入到multipart
	_ = writer.WriteField("name", fileName)
	err = writer.Close()
	fullURL := utils.GenerateGetURL(pageUrl, action, nil)
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			request, _ := http.NewRequest(http.MethodPost, fullURL+"?userId="+userID+"&productId="+productID, body)
			request.Header.Set("Content-Type", writer.FormDataContentType())
			a.FillRequestCookies(request)
			return request
		},
		a.config,
		func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
			if jsonResult1 == nil {
				return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
			}
			if err == nil {
				if jsonResult1["successed"] != nil {
					if !jsonResult1["successed"].(bool) {
						errLevel = platformapi.ErrLevelGeneralFail
						err = utils.NewErrorCode(jsonResult1["msg"].(string), "-1", 0)
						baseapi.SugarLogger.Debugf("yinbao AccessStorePageAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
					}
				} else {
					errLevel = platformapi.ErrLevelGeneralFail
					if strings.Contains(jsonResult1["fakeData"].(string), "登录") {
						err = utils.NewErrorCode("银豹Cookie可能失效了！", "-1", 0)
					}
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}

func IsErrCookie(err error) (isExist bool) {
	return utils.IsErrMatch(err, "-1", []string{"银豹Cookie可能失效了"})
}

type LoadSubStoresByUserIdDDLJsonResult struct {
	Balance                        float64     `json:"balance"`
	Storewebsite                   interface{} `json:"storewebsite"`
	Version                        interface{} `json:"version"`
	IsParent                       int         `json:"isParent"`
	SortNo                         int         `json:"sortNo"`
	UserLocation                   interface{} `json:"userLocation"`
	StoreDomain                    interface{} `json:"storeDomain"`
	ParentAccount                  interface{} `json:"parentAccount"`
	ParentUserID                   interface{} `json:"parentUserId"`
	AreaID                         string      `json:"areaId"`
	SubUsers                       interface{} `json:"subUsers"`
	CamerasSettings                interface{} `json:"camerasSettings"`
	ImageRecognitionRemainingTimes string      `json:"imageRecognitionRemainingTimes"`
	CrmVipNum                      interface{} `json:"crmVipNum"`
	ID                             int         `json:"id"`
	Account                        string      `json:"account"`
	Email                          interface{} `json:"email"`
	Address                        string      `json:"address"`
	Tel                            string      `json:"tel"`
	Company                        string      `json:"company"`
	Industry                       string      `json:"industry"`
	IP                             interface{} `json:"ip"`
	Vip                            interface{} `json:"vip"`
	CreatedDatetime                interface{} `json:"createdDatetime"`
	Enable                         interface{} `json:"enable"`
	IsOldRev                       interface{} `json:"isOldRev"`
	EnterpriseID                   interface{} `json:"enterpriseId"`
	Source                         interface{} `json:"source"`
	AppID                          interface{} `json:"appId"`
	AppKey                         interface{} `json:"appKey"`
	UserType                       int         `json:"userType"`
	IsFranchise                    int         `json:"isFranchise"`
	SecondIndustry                 interface{} `json:"secondIndustry"`
	Number                         interface{} `json:"number"`
	TimeZoneID                     interface{} `json:"timeZoneId"`
}

//获取所有门店的userID
//https://beta27.pospal.cn/Account/LoadSubStoresByUserIdDDLJson
func (a *API) LoadSubStoresByUserIdDDLJson() (results []*LoadSubStoresByUserIdDDLJsonResult, err error) {
	result, err := a.AccessStorePage("Account/LoadSubStoresByUserIdDDLJson", map[string]interface{}{
		"userId":   MainStoreVendorOrgCode,
		"withSelf": false,
	})
	if err == nil {
		utils.Map2StructByJson(result["stores"], &results, false)
	}
	return results, err
}

//获得分类ID
//https://beta27.pospal.cn/Category/CreateCategoryUid
func (a *API) CreateCategoryUid() (categoryID string, err error) {
	result, err := a.AccessStorePage("Category/CreateCategoryUid", nil)
	if err == nil {
		categoryID = result["uid"].(string)
	}
	return categoryID, err
}

//添加分类
//经测试，parentCategoryName为空或者平台上不存在都是默认建成1级分类
//https://beta27.pospal.cn/Category/AddNewCategory
func (a *API) AddNewCategory(userId, categoryName, parentCategoryName string) (catID string, err error) {
	uid, err := a.CreateCategoryUid()
	if err != nil {
		return "", err
	}
	_, err = a.AccessStorePage("Category/AddNewCategory", map[string]interface{}{
		"userId":             userId,
		"uid":                uid,
		"parentCategoryName": parentCategoryName,
		"categoryName":       categoryName,
		"categoryType":       0,
	})
	return uid, err
}

func IsErrCategoryExist(err error) (isExist bool) {
	return utils.IsErrMatch(err, "", []string{"您输入的商品分类名称已存在"})
}

//修改分类
//经测试，如果parentCategoryName为空或在平台上不存在，则此分类会单独从之前的分类中移出重建成一级分类，0_0||
//https://beta27.pospal.cn/Category/Update
func (a *API) UpdateCategory(userId, categoryUid, newCategoryName, parentCategoryName string) (err error) {
	_, err = a.AccessStorePage("Category/Update", map[string]interface{}{
		"userId":             userId,
		"categoryUid":        categoryUid,
		"parentCategoryName": parentCategoryName,
		"newCategoryName":    newCategoryName,
	})
	return err
}

//删除分类
// https://beta27.pospal.cn/Category/Delete
func (a *API) DeleteCategory(userId string, categoryUidsJson []string) (err error) {
	_, err = a.AccessStorePage("Category/Delete", map[string]interface{}{
		"userId":           userId,
		"categoryUidsJson": categoryUidsJson,
	})
	return err
}

type LoadCategorysWithOptionResult struct {
	ID              int    `json:"id"`
	UserID          int    `json:"userId"`
	UID             int64  `json:"uid"`
	ParentUID       int    `json:"parentUid"`
	Name            string `json:"name"`
	Enable          int    `json:"enable"`
	CreatedDatetime string `json:"createdDatetime"`
	UpdatedDatetime string `json:"updatedDatetime"`
	CategoryType    int    `json:"categoryType"`
	Categoryoption  struct {
		ID             int   `json:"id"`
		UserID         int   `json:"userId"`
		CategoryOrder  int   `json:"categoryOrder"`
		CategoryUID    int64 `json:"categoryUid"`
		HideFromClient int   `json:"hideFromClient"`
	} `json:"categoryoption"`
	TxtUID       string `json:"txtUid"`
	TxtParentUID string `json:"txtParentUid"`
}

//获取所有分类
//https://beta27.pospal.cn/Category/LoadCategorysWithOption
func (a *API) LoadCategorysWithOption(userId string) (loadCategorysWithOptionResult []*LoadCategorysWithOptionResult, err error) {
	result, err := a.AccessStorePage("Category/LoadCategorysWithOption", map[string]interface{}{
		"userId": userId,
	})
	if err == nil {
		utils.Map2StructByJson(result["categorys"], &loadCategorysWithOptionResult, false)
	}
	return loadCategorysWithOptionResult, err
}

//获取单个商品id
//https://beta27.pospal.cn/Product/LoadProductsByPage
func (a *API) LoadProductsByPage(userId, keyword string) (v string, err error) {
	result, err := a.AccessStorePage("Product/LoadProductsByPage", map[string]interface{}{
		"userId":    userId,
		"keyword":   keyword,
		"pageIndex": 1,
		"pageSize":  50,
		"enable":    1,
	})
	if err == nil {
		body := result["contentView"].(string)
		if strings.Contains(body, "未查询到符合条件的记录") {
			err = utils.NewErrorCode("未查询到符合条件的记录！", "-1", 0)
			return "", err
		}
		result := regexpSkuID.FindStringSubmatch(body)
		return result[1], err
	}
	return "", err
}

type FindProductResult struct {
	Category struct {
		ID              int    `json:"id"`
		UserID          int    `json:"userId"`
		UID             int64  `json:"uid"`
		ParentUID       int64  `json:"parentUid"`
		Name            string `json:"name"`
		Enable          int    `json:"enable"`
		CreatedDatetime string `json:"createdDatetime"`
		UpdatedDatetime string `json:"updatedDatetime"`
		CategoryType    int    `json:"categoryType"`
		TxtUID          string `json:"txtUid"`
	} `json:"category"`
	Productimages []struct {
		Barcode         string `json:"barcode"`
		CreatedDatetime string `json:"createdDatetime"`
		ID              int    `json:"id"`
		IsCover         bool   `json:"isCover"`
		Path            string `json:"path"`
		ProductName     string `json:"productName"`
		ProductUID      int64  `json:"productUid"`
		UID             int64  `json:"uid"`
		UpdatedDatetime string `json:"updatedDatetime"`
		UserID          int    `json:"userId"`
	} `json:"productimages"`
	CategoryShowID          int           `json:"categoryShowId"`
	ParentHas               int           `json:"parentHas"`
	TxtUID                  string        `json:"txtUid"`
	UpdateStock             float64       `json:"updateStock"`
	IsOutOfStock            bool          `json:"isOutOfStock"`
	ProductUnitExchangeList []interface{} `json:"productUnitExchangeList"`
	BaseUnitName            string        `json:"baseUnitName"`
	IsCurrentPrice          bool          `json:"isCurrentPrice"`
	DisableEntireDiscount   bool          `json:"disableEntireDiscount"`
	IsPrior                 bool          `json:"isPrior"`
	ProductTags             []interface{} `json:"productTags"`
	CustomerPrices          []interface{} `json:"customerPrices"`
	EnableBatch             int           `json:"enableBatch"`
	HideFromClient          int           `json:"hideFromClient"`
	SpecNum                 int           `json:"specNum"`
	IsEnableVirtualStock    bool          `json:"isEnableVirtualStock"`
	IsPassPromotionProduct  bool          `json:"isPassPromotionProduct"`
	IsBindPassProduct       bool          `json:"isBindPassProduct"`
	IgnoreStock             bool          `json:"ignoreStock"`
	DataIndex               int           `json:"dataIndex"`
	SellPriceIsNull         bool          `json:"sellPriceIsNull"`
	Spu                     string        `json:"spu"`
	ID                      int           `json:"id"`
	UID                     int64         `json:"uid"`
	CategoryUID             int64         `json:"categoryUid"`
	UserID                  int           `json:"userId"`
	Name                    string        `json:"name"`
	Barcode                 string        `json:"barcode"`
	BuyPrice                float64       `json:"buyPrice"`
	SellPrice               float64       `json:"sellPrice"`
	Stock                   float64       `json:"stock"`
	MaxStock                float64       `json:"maxStock"`
	MinStock                float64       `json:"minStock"`
	Pinyin                  string        `json:"pinyin"`
	SellPrice2              float64       `json:"sellPrice2"`
	IsPoint                 int           `json:"isPoint"`
	Enable                  int           `json:"enable"`
	CreatedDatetime         string        `json:"createdDatetime"`
	ProductTastes           []interface{} `json:"productTastes"`
}

//获取单个商品信息
//https://beta27.pospal.cn/Product/FindProduct
func (a *API) FindProduct(productId string) (findProductResult *FindProductResult, err error) {
	result, err := a.AccessStorePage("Product/FindProduct", map[string]interface{}{
		"productId": productId,
	})
	if err == nil {
		utils.Map2StructByJson(result["product"], &findProductResult, false)
	}
	return findProductResult, err
}

type SaveProductParam struct {
	CategoryUid  string `json:"categoryUid"`
	CategoryName string `json:"categoryName"`
	Enable       int    `json:"enable"`
}

//更新单个商品信息（称编码和图片）
//Request URL: https://beta27.pospal.cn/Product/SaveProduct
func (a *API) SaveProduct(userId, keyword string, saveProductParam *SaveProductParam) (err error) {
	var (
		categoryUid, categoryName string
		enable                    string
	)
	productId, err := a.LoadProductsByPage(userId, keyword)
	if err != nil {
		return err
	}
	findProductResult, err := a.FindProduct(productId)
	if err != nil {
		return err
	}
	if saveProductParam != nil {
		if saveProductParam.Enable != 0 {
			enable = utils.Int2Str(saveProductParam.Enable)
		} else {
			enable = utils.Int2Str(findProductResult.Enable)
		}
		if saveProductParam.CategoryUid != "" {
			categoryUid = saveProductParam.CategoryUid
		} else {
			categoryUid = utils.Int2Str(findProductResult.Enable)
		}
		if saveProductParam.CategoryName != "" {
			categoryName = saveProductParam.CategoryName
		} else {
			categoryName = utils.Int2Str(findProductResult.Enable)
		}
	} else {
		categoryUid = utils.Int64ToStr(findProductResult.CategoryUID)
		categoryName = findProductResult.Category.Name
		enable = utils.Int2Str(findProductResult.Enable)
	}
	params2 := map[string]interface{}{
		"pluCode": findProductResult.Barcode[3:],
	}
	params := map[string]interface{}{
		"id":                      utils.Int2Str(findProductResult.ID),
		"enable":                  enable,
		"userId":                  utils.Int2Str(findProductResult.UserID),
		"barcode":                 findProductResult.Barcode,
		"name":                    findProductResult.Name,
		"categoryUid":             categoryUid,
		"categoryName":            categoryName,
		"sellPrice":               utils.Float64ToStr(findProductResult.SellPrice),
		"buyPrice":                utils.Float64ToStr(findProductResult.BuyPrice),
		"isCustomerDiscount":      "1",
		"customerPrice":           "",
		"sellPrice2":              utils.Float64ToStr(findProductResult.SellPrice2),
		"pinyin":                  findProductResult.Pinyin,
		"supplierUid":             "",
		"supplierName":            "无",
		"productionDate":          "",
		"shelfLife":               "",
		"maxStock":                utils.Float64ToStr(findProductResult.MaxStock),
		"minStock":                utils.Float64ToStr(findProductResult.MinStock),
		"stock":                   utils.Float64ToStr(findProductResult.Stock),
		"description":             "",
		"noStock":                 "0",
		"productCommonAttribute":  params2,
		"baseUnitName":            findProductResult.BaseUnitName,
		"customerPrices":          []string{},
		"productUnitExchangeList": []string{},
		"productTags":             []string{},
		"productTastes":           []string{},
		"attribute1":              "",
		"attribute2":              "",
		"attribute3":              "",
		"attribute4":              "",
		"attribute6":              "",
	}
	result, _ := json.Marshal(params)
	_, err = a.AccessStorePage("Product/SaveProduct", map[string]interface{}{
		"productJson": string(result),
	})
	return err
}

//上传图片
//https://beta27.pospal.cn/Product/UploadProductImage?userId=3933189&productId=8788044
func (a *API) UploadProductImage(userID, productId string, data []byte, fileName string) (err error) {
	_, err = a.AccessStorePage2("Product/UploadProductImage", userID, productId, data, fileName)
	return err
}

//设置图片为封面
// https://beta27.pospal.cn/Product/ResetCoverImage
func (a *API) ResetCoverImage(userId, keyword string) (err error) {
	productId, err := a.LoadProductsByPage(userId, keyword)
	if err != nil {
		return err
	}
	findProductResult, err := a.FindProduct(productId)
	if err != nil {
		return err
	}
	if len(findProductResult.Productimages) > 0 {
		_, err = a.AccessStorePage("Product/ResetCoverImage", map[string]interface{}{
			"productImageId":  findProductResult.Productimages[len(findProductResult.Productimages)-1].ID,
			"forMulColorSize": false,
		})
	}
	return err
}

//登录？
//https://beta27.pospal.cn/account/SignIn?noLog=
//userName: 18048531223
// password: Rosy201507
// returnUrl:
// screenSize: 1600*900
//Accept: application/json, text/javascript, */*; q=0.01
//Accept-Encoding: gzip, deflate, br
//Accept-Language: zh-CN,zh;q=0.9
//Connection: keep-alive
//Content-Length: 71
//Content-Type: application/x-www-form-urlencoded; charset=UTF-8
//Host: beta27.pospal.cn
//Origin: https://beta27.pospal.cn
//Referer: https://beta27.pospal.cn/account/signin
//Sec-Fetch-Mode: cors
//Sec-Fetch-Site: same-origin
//User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
//X-Requested-With: XMLHttpRequest
func (a *API) TryGetCookie() (cookie string, err error) {
	params := map[string]interface{}{
		"userName":   18048531223,
		"password":   "Rosy201507",
		"returnUrl":  "",
		"screenSize": "1600*900",
	}
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			request, _ := http.NewRequest(http.MethodPost, "https://beta27.pospal.cn/account/SignIn?noLog=", strings.NewReader(utils.Map2URLValues(params).Encode()))
			request.Header.Set("Accept", "application/json, text/javascript, */*; q=0.01")
			request.Header.Set("Accept-Encoding", "gzip, deflate, br")
			request.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
			request.Header.Set("Connection", "keep-alive")
			request.Header.Set("Content-Length", "56")
			request.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
			request.Header.Set("Host", "beta27.pospal.cn")
			request.Header.Set("Origin", "https://beta27.pospal.cn")
			request.Header.Set("Referer", "https://beta27.pospal.cn/account/signin")
			request.Header.Set("Sec-Fetch-Mode", "cors")
			request.Header.Set("Sec-Fetch-Site", "same-origin")
			request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36")
			request.Header.Set("X-Requested-With", "XMLHttpRequest")
			return request
		},
		a.config,
		func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
			cookies := response.Cookies()
			for _, v := range cookies {
				if v.Name == ".POSPALAUTH30220" && v.Value != "" {
					cookie = v.Value
				}
			}
			return errLevel, err
		})
	return cookie, err
}

//银豹改变商品状态？
//https://beta27.pospal.cn/Product/BatchUpdateProductEnable
func (a *API) BatchUpdateProductEnable(userID, productId string, enable int) (err error) {
	_, err = a.AccessStorePage("Product/BatchUpdateProductEnable", map[string]interface{}{
		"enable":                                enable,
		"productRange[userId]":                  userID,
		"productRange[enable]":                  enable,
		"productRange[isProductRequestedStore]": false,
		"productRange[isAddvancedSearch]":       false,
		"productRange[isUpdateAllProduct]":      false,
		"productRange[productUidsJson]":         []string{productId},
	})
	return err
}
