package reporter

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/url"
	"os"

	"hnyfkj.com.cn/rtu/bxs-sy/baseapp"
)

type rpcRequest struct {
	JSONRPC string          `json:"jsonrpc"`          // 版本号, 固定: "2.0"
	Method  string          `json:"method"`           // 调用方法, 执行函数名
	Params  json.RawMessage `json:"params,omitempty"` // 请求参数, 可选可为空
	ID      int             `json:"id"`               // 请求ID, 用于标识请求
}

type rpcError struct {
	Code    int    `json:"code"`    // 错误码
	Message string `json:"message"` // 错误信息
}

type rpcResponse struct {
	JSONRPC string          `json:"jsonrpc"`          // 版本号, 固定: "2.0"
	Result  json.RawMessage `json:"result,omitempty"` // 响应结果, 可选可为空
	Error   *rpcError       `json:"error,omitempty"`  // 错误信息, 可选可为空
	ID      int             `json:"id"`               // 应答ID, 响应匹配请求
}

func makeLoginReq(imei, iccid, rssi, appVersion, inheritDUI string) ([]byte, error) {
	type params struct {
		DeviceType string `json:"deviceType"`
		IMEI       string `json:"imei"`
		ICCID      string `json:"iccid"`
		RSSI       string `json:"rssi"`
		AppVersion string `json:"appVersion"`
		InheritID  string `json:"inheritDUI,omitempty"` // 继承的DUI, 可选可为空
	}

	paramsVar := params{
		DeviceType: "33", // 便携式色诱产品类型为: 33
		IMEI:       imei,
		ICCID:      iccid,
		RSSI:       rssi,
		AppVersion: appVersion,
		InheritID:  inheritDUI,
	}

	paramsBytes, err := json.Marshal(paramsVar)
	if err != nil {
		return nil, err
	}

	req := rpcRequest{
		JSONRPC: "2.0",
		Method:  "login",
		Params:  paramsBytes,
		ID:      1,
	}

	return json.Marshal(req)
}

func parseLoginResp(data []byte) (string, string, error) {
	var resp rpcResponse
	if err := json.Unmarshal(data, &resp); err != nil {
		return "", "", err
	}

	if resp.Error != nil {
		return "", "", fmt.Errorf("服务器返回错误: %d, %s", resp.Error.Code, resp.Error.Message)
	}

	var result struct {
		IMEI string `json:"imei"`
		DUI  string `json:"DUI"`
	}
	if err := json.Unmarshal(resp.Result, &result); err != nil {
		return "", "", err
	}

	if len(result.DUI) != 14 || !isDecimal(result.DUI) {
		return "", "", fmt.Errorf("无效DUI: %q", result.DUI)
	}

	return result.IMEI, result.DUI, nil
}

func makeLogoutMsg(imei string) ([]byte, error) {
	type params struct {
		IMEI string `json:"imei"`
	}

	paramsVar := params{
		IMEI: imei,
	}

	paramsBytes, err := json.Marshal(paramsVar)
	if err != nil {
		return nil, err
	}

	req := rpcRequest{
		JSONRPC: "2.0",
		Method:  "logout",
		Params:  paramsBytes,
		ID:      1,
	}

	return json.Marshal(req)
}

func makeCustomError(err error) *rpcError {
	if err == nil {
		return nil
	}
	return &rpcError{-32000, fmt.Sprintf("Custom error: %v", err)}
}

type mcuParams struct {
	Version              string `json:"version"`                  // 版本号 x.x.x.x, 定义: [major(8bit)].[minor(8bit)].[patch(8bit)].[build(8bit)]
	CtrlMode             string `json:"ctrlMode"`                 // 定时控制模式(0=光控, 1=时控)
	LightDuration        string `json:"lightDuration"`            // 光控定时时长(小时, 1-10, 仅光控模式有效)
	StartHour            string `json:"startHour"`                // 时控开始时间(小时, 0-23, 仅时控模式有效)
	EndHour              string `json:"endHour"`                  // 时控结束时间(小时, 0-23, 仅时控模式有效)
	PhotoIntervalMinutes string `json:"takePhotoIntervalMinutes"` // 拍照间隔(分钟)
}

func isDecimal(s string) bool {
	for _, ch := range s {
		if ch < '0' || ch > '9' {
			return false
		}
	}
	return s != "" // 不允许空字符串
}

func parseMCUParams(data []byte) (mcuParams, error) {
	var req rpcRequest
	if err := json.Unmarshal(data, &req); err != nil {
		return mcuParams{}, err
	}

	if len(req.Params) == 0 {
		return mcuParams{}, fmt.Errorf("missing params")
	}

	var params mcuParams
	if err := json.Unmarshal(req.Params, &params); err != nil {
		return mcuParams{}, err
	}

	var verCode baseapp.VersionCode
	err := verCode.FromString(params.Version)
	if err != nil || !isDecimal(params.CtrlMode) || !isDecimal(params.LightDuration) ||
		!isDecimal(params.StartHour) || !isDecimal(params.EndHour) || !isDecimal(params.PhotoIntervalMinutes) {
		return mcuParams{}, fmt.Errorf("invalid params")
	}

	return params, nil
}

func parseUpgradeAppResp(data []byte) (serverAddr, loginUser, loginPass, remoteFile, md5value string, err error) {
	var req rpcRequest
	if err := json.Unmarshal(data, &req); err != nil {
		return "", "", "", "", "", err
	}

	if len(req.Params) == 0 {
		return "", "", "", "", "", fmt.Errorf("missing params")
	}

	var params struct {
		URL string `json:"url"` // 升级包的URL地址
		MD5 string `json:"md5"` // 升级包的MD5校验值, 32个十六进制数字组成, 16字节
	}
	if err := json.Unmarshal(req.Params, &params); err != nil {
		return "", "", "", "", "", err
	}

	u, err := url.Parse(params.URL)
	if err != nil {
		return "", "", "", "", "", fmt.Errorf("invalid URL: %s", params.URL)
	}

	if u.Scheme != "ftp" {
		return "", "", "", "", "", fmt.Errorf("unsupported scheme: %s", u.Scheme)
	}

	host := u.Hostname()
	port := u.Port()
	if port == "" {
		port = "21"
	}
	serverAddr = fmt.Sprintf("%s:%s", host, port)

	loginUser = u.User.Username()
	loginPass, _ = u.User.Password()

	remoteFile = u.Path
	if remoteFile == "" {
		return "", "", "", "", "", fmt.Errorf("missing remote file path")
	}
	md5value = params.MD5

	return serverAddr, loginUser, loginPass, remoteFile, md5value, nil
}

func fileMD5(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", err
	}
	return hex.EncodeToString(h.Sum(nil)), nil
}
