package devicesdk

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

type DeviceClient struct {
	baseURL    string
	encryptKey string
	client     *http.Client
}

type DeviceInfo struct {
	UID         string `json:"uid"`
	DeviceModel string `json:"device_model"`
	LicenseCode string `json:"license_code,omitempty"`
}

type ValidateResponse struct {
	Status      string    `json:"status"`
	LicenseType string    `json:"license_type"`
	ExpireTime  time.Time `json:"expire_time"`
	StartCount  int       `json:"start_count"`
	MaxUses     int       `json:"max_uses"`
	Timestamp   int64     `json:"timestamp"`
}

type ApiResponse struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Error   string      `json:"error"`
	Data    interface{} `json:"data"`
}

func NewDeviceClient(baseURL, encryptKey string) *DeviceClient {
	return &DeviceClient{
		baseURL:    baseURL,
		encryptKey: encryptKey,
		client:     &http.Client{Timeout: time.Second * 30},
	}
}

func (c *DeviceClient) RegisterDevice(info *DeviceInfo) error {
	data, err := json.Marshal(info)
	if err != nil {
		return fmt.Errorf("序列化请求数据失败: %v", err)
	}

	resp, err := c.post("/api/devices/register", data)
	if err != nil {
		return err
	}

	if resp.Code != 0 {
		return fmt.Errorf(resp.Error)
	}

	return nil
}

func (c *DeviceClient) ValidateDevice(uid string) (*ValidateResponse, error) {
	resp, err := c.get(fmt.Sprintf("/api/devices/%s/validate", uid))
	if err != nil {
		return nil, err
	}

	if resp.Code != 0 {
		return nil, fmt.Errorf(resp.Error)
	}

	decrypted, err := c.decryptResponse(resp.Data.(string))
	if err != nil {
		return nil, err
	}

	var validateResp ValidateResponse
	if err := json.Unmarshal([]byte(decrypted), &validateResp); err != nil {
		return nil, fmt.Errorf("解析响应数据失败: %v", err)
	}

	return &validateResp, nil
}

func (c *DeviceClient) UpdateStartCount(uid string) (int, error) {
	resp, err := c.post(fmt.Sprintf("/api/devices/%s/start", uid), nil)
	if err != nil {
		return 0, err
	}

	if resp.Code != 0 {
		return 0, fmt.Errorf(resp.Error)
	}

	data := resp.Data.(map[string]interface{})
	return int(data["start_count"].(float64)), nil
}

func (c *DeviceClient) BindLicense(uid, licenseCode string) error {
	data, err := json.Marshal(map[string]string{
		"license_code": licenseCode,
	})
	if err != nil {
		return fmt.Errorf("序列化请求数据失败: %v", err)
	}

	resp, err := c.post(fmt.Sprintf("/api/devices/%s/license", uid), data)
	if err != nil {
		return err
	}

	if resp.Code != 0 {
		return fmt.Errorf(resp.Error)
	}

	return nil
}

// HTTP 请求辅助方法
func (c *DeviceClient) get(path string) (*ApiResponse, error) {
	resp, err := c.client.Get(c.baseURL + path)
	if err != nil {
		return nil, fmt.Errorf("HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	return c.parseResponse(resp)
}

func (c *DeviceClient) post(path string, data []byte) (*ApiResponse, error) {
	var resp *http.Response
	var err error

	if data == nil {
		resp, err = c.client.Post(c.baseURL+path, "application/json", nil)
	} else {
		resp, err = c.client.Post(c.baseURL+path, "application/json", bytes.NewBuffer(data))
	}

	if err != nil {
		return nil, fmt.Errorf("HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	return c.parseResponse(resp)
}

func (c *DeviceClient) parseResponse(resp *http.Response) (*ApiResponse, error) {
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应数据失败: %v", err)
	}

	var apiResp ApiResponse
	if err := json.Unmarshal(body, &apiResp); err != nil {
		return nil, fmt.Errorf("解析响应数据失败: %v", err)
	}

	return &apiResp, nil
}

func (c *DeviceClient) decryptResponse(encrypted string) (string, error) {
	ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
	if err != nil {
		return "", fmt.Errorf("base64解码失败: %v", err)
	}

	block, err := aes.NewCipher([]byte(c.encryptKey))
	if err != nil {
		return "", fmt.Errorf("创建AES cipher失败: %v", err)
	}

	if len(ciphertext) < aes.BlockSize {
		return "", fmt.Errorf("密文长度不足")
	}

	iv := ciphertext[:aes.BlockSize]
	ciphertext = ciphertext[aes.BlockSize:]

	stream := cipher.NewCFBDecrypter(block, iv)
	stream.XORKeyStream(ciphertext, ciphertext)

	return string(ciphertext), nil
}
