package integration

import (
	"encoding/json"
	"fmt"
	"testing"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/response"
	"github.com/break/junhong_cmp_fiber/tests/testutils/integ"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func uniqueEDH5TestPrefix() string {
	return fmt.Sprintf("H5ED%d", time.Now().UnixNano()%1000000000)
}

func TestEnterpriseDeviceH5_ListDevices(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	prefix := uniqueEDH5TestPrefix()
	shop := env.CreateTestShop(prefix+"_SHOP", 1, nil)
	enterprise := env.CreateTestEnterprise(prefix+"_ENTERPRISE", &shop.ID)
	enterpriseUser := env.CreateTestAccount(prefix+"_USER", "Password123", constants.UserTypeEnterprise, nil, &enterprise.ID)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "测试设备",
		Status:     2,
		ShopID:     &shop.ID,
	}
	require.NoError(t, env.TX.Create(device).Error)

	now := time.Now()
	deviceAuth := &model.EnterpriseDeviceAuthorization{
		EnterpriseID:   enterprise.ID,
		DeviceID:       device.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
	}
	require.NoError(t, env.TX.Create(deviceAuth).Error)

	t.Run("企业用户获取授权设备列表", func(t *testing.T) {
		resp, err := env.AsUser(enterpriseUser).Request("GET", "/api/h5/devices?page=1&page_size=10", nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		data := result.Data.(map[string]interface{})
		assert.Equal(t, float64(1), data["total"])
	})
}

func TestEnterpriseDeviceH5_GetDeviceDetail(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	prefix := uniqueEDH5TestPrefix()
	shop := env.CreateTestShop(prefix+"_SHOP", 1, nil)
	enterprise := env.CreateTestEnterprise(prefix+"_ENTERPRISE", &shop.ID)
	enterpriseUser := env.CreateTestAccount(prefix+"_USER", "Password123", constants.UserTypeEnterprise, nil, &enterprise.ID)

	carrier := &model.Carrier{CarrierName: "测试运营商", CarrierType: "CMCC", Status: 1}
	require.NoError(t, env.TX.Create(carrier).Error)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "测试设备",
		Status:     2,
		ShopID:     &shop.ID,
	}
	require.NoError(t, env.TX.Create(device).Error)

	card := &model.IotCard{ICCID: prefix + "0001", CardType: "normal", CarrierID: carrier.ID, Status: 2, ShopID: &shop.ID, NetworkStatus: 1}
	require.NoError(t, env.TX.Create(card).Error)

	now := time.Now()
	binding := &model.DeviceSimBinding{DeviceID: device.ID, IotCardID: card.ID, SlotPosition: 1, BindStatus: 1, BindTime: &now}
	require.NoError(t, env.TX.Create(binding).Error)

	deviceAuth := &model.EnterpriseDeviceAuthorization{
		EnterpriseID:   enterprise.ID,
		DeviceID:       device.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
	}
	require.NoError(t, env.TX.Create(deviceAuth).Error)

	cardAuth := &model.EnterpriseCardAuthorization{
		EnterpriseID:   enterprise.ID,
		CardID:         card.ID,
		DeviceAuthID:   &deviceAuth.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
	}
	require.NoError(t, env.TX.Create(cardAuth).Error)

	t.Run("成功获取设备详情", func(t *testing.T) {
		url := fmt.Sprintf("/api/h5/devices/%d", device.ID)
		resp, err := env.AsUser(enterpriseUser).Request("GET", url, nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		data := result.Data.(map[string]interface{})
		deviceInfo := data["device"].(map[string]interface{})
		assert.Equal(t, float64(device.ID), deviceInfo["device_id"])
		assert.Equal(t, device.DeviceNo, deviceInfo["device_no"])

		cards := data["cards"].([]interface{})
		assert.Len(t, cards, 1)
	})

	t.Run("设备未授权返回错误", func(t *testing.T) {
		device2 := &model.Device{
			DeviceNo:   prefix + "_D002",
			DeviceName: "未授权设备",
			Status:     2,
		}
		require.NoError(t, env.TX.Create(device2).Error)

		url := fmt.Sprintf("/api/h5/devices/%d", device2.ID)
		resp, err := env.AsUser(enterpriseUser).Request("GET", url, nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code)
	})
}

func TestEnterpriseDeviceH5_SuspendCard(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	prefix := uniqueEDH5TestPrefix()
	shop := env.CreateTestShop(prefix+"_SHOP", 1, nil)
	enterprise := env.CreateTestEnterprise(prefix+"_ENTERPRISE", &shop.ID)
	enterpriseUser := env.CreateTestAccount(prefix+"_USER", "Password123", constants.UserTypeEnterprise, nil, &enterprise.ID)

	carrier := &model.Carrier{CarrierName: "测试运营商", CarrierType: "CMCC", Status: 1}
	require.NoError(t, env.TX.Create(carrier).Error)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "测试设备",
		Status:     2,
		ShopID:     &shop.ID,
	}
	require.NoError(t, env.TX.Create(device).Error)

	card := &model.IotCard{ICCID: prefix + "0001", CardType: "normal", CarrierID: carrier.ID, Status: 2, ShopID: &shop.ID, NetworkStatus: 1}
	require.NoError(t, env.TX.Create(card).Error)

	now := time.Now()
	binding := &model.DeviceSimBinding{DeviceID: device.ID, IotCardID: card.ID, SlotPosition: 1, BindStatus: 1, BindTime: &now}
	require.NoError(t, env.TX.Create(binding).Error)

	deviceAuth := &model.EnterpriseDeviceAuthorization{
		EnterpriseID:   enterprise.ID,
		DeviceID:       device.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
	}
	require.NoError(t, env.TX.Create(deviceAuth).Error)

	cardAuth := &model.EnterpriseCardAuthorization{
		EnterpriseID:   enterprise.ID,
		CardID:         card.ID,
		DeviceAuthID:   &deviceAuth.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
	}
	require.NoError(t, env.TX.Create(cardAuth).Error)

	t.Run("成功停机", func(t *testing.T) {
		reqBody := dto.DeviceCardOperationReq{Reason: "测试停机"}
		body, _ := json.Marshal(reqBody)

		url := fmt.Sprintf("/api/h5/devices/%d/cards/%d/suspend", device.ID, card.ID)
		resp, err := env.AsUser(enterpriseUser).Request("POST", url, body)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		data := result.Data.(map[string]interface{})
		assert.Equal(t, true, data["success"])
	})

	t.Run("卡不属于设备返回错误", func(t *testing.T) {
		card2 := &model.IotCard{ICCID: prefix + "0002", CardType: "normal", CarrierID: carrier.ID, Status: 2}
		require.NoError(t, env.TX.Create(card2).Error)

		reqBody := dto.DeviceCardOperationReq{Reason: "测试停机"}
		body, _ := json.Marshal(reqBody)

		url := fmt.Sprintf("/api/h5/devices/%d/cards/%d/suspend", device.ID, card2.ID)
		resp, err := env.AsUser(enterpriseUser).Request("POST", url, body)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code)
	})
}

func TestEnterpriseDeviceH5_ResumeCard(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	prefix := uniqueEDH5TestPrefix()
	shop := env.CreateTestShop(prefix+"_SHOP", 1, nil)
	enterprise := env.CreateTestEnterprise(prefix+"_ENTERPRISE", &shop.ID)
	enterpriseUser := env.CreateTestAccount(prefix+"_USER", "Password123", constants.UserTypeEnterprise, nil, &enterprise.ID)

	carrier := &model.Carrier{CarrierName: "测试运营商", CarrierType: "CMCC", Status: 1}
	require.NoError(t, env.TX.Create(carrier).Error)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "测试设备",
		Status:     2,
		ShopID:     &shop.ID,
	}
	require.NoError(t, env.TX.Create(device).Error)

	card := &model.IotCard{ICCID: prefix + "0001", CardType: "normal", CarrierID: carrier.ID, Status: 2, ShopID: &shop.ID, NetworkStatus: 0}
	require.NoError(t, env.TX.Create(card).Error)

	now := time.Now()
	binding := &model.DeviceSimBinding{DeviceID: device.ID, IotCardID: card.ID, SlotPosition: 1, BindStatus: 1, BindTime: &now}
	require.NoError(t, env.TX.Create(binding).Error)

	deviceAuth := &model.EnterpriseDeviceAuthorization{
		EnterpriseID:   enterprise.ID,
		DeviceID:       device.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
	}
	require.NoError(t, env.TX.Create(deviceAuth).Error)

	cardAuth := &model.EnterpriseCardAuthorization{
		EnterpriseID:   enterprise.ID,
		CardID:         card.ID,
		DeviceAuthID:   &deviceAuth.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
	}
	require.NoError(t, env.TX.Create(cardAuth).Error)

	t.Run("成功复机", func(t *testing.T) {
		reqBody := dto.DeviceCardOperationReq{Reason: "测试复机"}
		body, _ := json.Marshal(reqBody)

		url := fmt.Sprintf("/api/h5/devices/%d/cards/%d/resume", device.ID, card.ID)
		resp, err := env.AsUser(enterpriseUser).Request("POST", url, body)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode)

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.Equal(t, 0, result.Code)

		data := result.Data.(map[string]interface{})
		assert.Equal(t, true, data["success"])
	})

	t.Run("设备未授权返回错误", func(t *testing.T) {
		device2 := &model.Device{
			DeviceNo:   prefix + "_D002",
			DeviceName: "未授权设备",
			Status:     2,
		}
		require.NoError(t, env.TX.Create(device2).Error)

		reqBody := dto.DeviceCardOperationReq{Reason: "测试复机"}
		body, _ := json.Marshal(reqBody)

		url := fmt.Sprintf("/api/h5/devices/%d/cards/%d/resume", device2.ID, card.ID)
		resp, err := env.AsUser(enterpriseUser).Request("POST", url, body)
		require.NoError(t, err)
		defer resp.Body.Close()

		var result response.Response
		err = json.NewDecoder(resp.Body).Decode(&result)
		require.NoError(t, err)
		assert.NotEqual(t, 0, result.Code)
	})
}
