package integration

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

	"github.com/break/junhong_cmp_fiber/internal/model"
	"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 TestDevice_List(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	// 创建测试设备
	devices := []*model.Device{
		{DeviceNo: "TEST_DEVICE_001", DeviceName: "测试设备1", DeviceType: "router", MaxSimSlots: 4, Status: constants.DeviceStatusInStock},
		{DeviceNo: "TEST_DEVICE_002", DeviceName: "测试设备2", DeviceType: "router", MaxSimSlots: 2, Status: constants.DeviceStatusInStock},
		{DeviceNo: "TEST_DEVICE_003", DeviceName: "测试设备3", DeviceType: "mifi", MaxSimSlots: 1, Status: constants.DeviceStatusDistributed},
	}
	for _, device := range devices {
		require.NoError(t, env.TX.Create(device).Error)
	}

	t.Run("获取设备列表-无过滤", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/devices?page=1&page_size=20", 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)
	})

	t.Run("获取设备列表-按设备类型过滤", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/devices?device_type=router", 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)
	})

	t.Run("获取设备列表-按状态过滤", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", fmt.Sprintf("/api/admin/devices?status=%d", constants.DeviceStatusInStock), 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)
	})

	t.Run("未认证请求应返回错误", func(t *testing.T) {
		resp, err := env.ClearAuth().Request("GET", "/api/admin/devices", 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 TestDevice_GetByID(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	// 创建测试设备
	device := &model.Device{
		DeviceNo:    "TEST_DEVICE_GET_001",
		DeviceName:  "测试设备详情",
		DeviceType:  "router",
		MaxSimSlots: 4,
		Status:      constants.DeviceStatusInStock,
	}
	require.NoError(t, env.TX.Create(device).Error)

	t.Run("获取设备详情-成功", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/devices/%d", device.ID)
		resp, err := env.AsSuperAdmin().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)

		// 验证返回数据
		dataMap, ok := result.Data.(map[string]interface{})
		require.True(t, ok)
		assert.Equal(t, "TEST_DEVICE_GET_001", dataMap["device_no"])
	})

	t.Run("获取不存在的设备-应返回错误", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/devices/999999", 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 TestDevice_Delete(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	device := &model.Device{
		DeviceNo:    "TEST_DEVICE_DEL_001",
		DeviceName:  "测试删除设备",
		DeviceType:  "router",
		MaxSimSlots: 4,
		Status:      constants.DeviceStatusInStock,
	}
	require.NoError(t, env.TX.Create(device).Error)

	t.Run("删除设备-成功", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/devices/%d", device.ID)
		resp, err := env.AsSuperAdmin().Request("DELETE", 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)

		var deletedDevice model.Device
		err = env.RawDB().Unscoped().First(&deletedDevice, device.ID).Error
		require.NoError(t, err)
		assert.NotNil(t, deletedDevice.DeletedAt)
	})
}

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

	task := &model.DeviceImportTask{
		TaskNo:     "TEST_DEVICE_IMPORT_001",
		Status:     model.ImportTaskStatusCompleted,
		BatchNo:    "TEST_BATCH_001",
		TotalCount: 100,
	}
	require.NoError(t, env.TX.Create(task).Error)

	t.Run("获取导入任务列表", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/devices/import/tasks?page=1&page_size=20", 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)
	})

	t.Run("获取导入任务详情", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/devices/import/tasks/%d", task.ID)
		resp, err := env.AsSuperAdmin().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)
	})
}

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

	// 创建测试设备
	device := &model.Device{
		DeviceNo:    "TEST_IMEI_001",
		DeviceName:  "测试IMEI查询设备",
		DeviceType:  "router",
		MaxSimSlots: 4,
		Status:      constants.DeviceStatusInStock,
	}
	require.NoError(t, env.TX.Create(device).Error)

	t.Run("通过IMEI查询设备详情-成功", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/devices/by-imei/%s", device.DeviceNo)
		resp, err := env.AsSuperAdmin().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)

		// 验证返回数据
		dataMap, ok := result.Data.(map[string]interface{})
		require.True(t, ok)
		assert.Equal(t, "TEST_IMEI_001", dataMap["device_no"])
		assert.Equal(t, "测试IMEI查询设备", dataMap["device_name"])
	})

	t.Run("通过不存在的IMEI查询-应返回错误", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/devices/by-imei/NONEXISTENT_IMEI", 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, "不存在的IMEI应返回错误码")
	})

	t.Run("未认证请求-应返回错误", func(t *testing.T) {
		url := fmt.Sprintf("/api/admin/devices/by-imei/%s", device.DeviceNo)
		resp, err := env.ClearAuth().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 TestDevice_BatchSetSeriesBinding(t *testing.T) {
	env := integ.NewIntegrationTestEnv(t)

	shop := env.CreateTestShop("测试店铺", 1, nil)
	agentAccount := env.CreateTestAccount(fmt.Sprintf("agent_dev_%d", time.Now().UnixNano()), "password123", constants.UserTypeAgent, &shop.ID, nil)

	series := createTestPackageSeries(t, env, "测试系列")
	createTestAllocation(t, env, shop.ID, series.ID, 0)

	devices := []*model.Device{
		{DeviceNo: fmt.Sprintf("DEV_%d_001", time.Now().UnixNano()), DeviceName: "测试设备1", DeviceType: "router", MaxSimSlots: 4, Status: constants.DeviceStatusInStock, ShopID: &shop.ID},
		{DeviceNo: fmt.Sprintf("DEV_%d_002", time.Now().UnixNano()), DeviceName: "测试设备2", DeviceType: "mifi", MaxSimSlots: 2, Status: constants.DeviceStatusInStock, ShopID: &shop.ID},
		{DeviceNo: fmt.Sprintf("DEV_%d_003", time.Now().UnixNano()), DeviceName: "测试设备3", DeviceType: "router", MaxSimSlots: 4, Status: constants.DeviceStatusInStock, ShopID: &shop.ID},
	}
	for _, device := range devices {
		require.NoError(t, env.TX.Create(device).Error)
	}

	t.Run("批量设置设备系列绑定-成功", func(t *testing.T) {
		body := map[string]interface{}{
			"device_ids": []uint{devices[0].ID, devices[1].ID},
			"series_id":  series.ID,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		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, "应返回成功: %s", result.Message)

		if result.Data != nil {
			dataMap := result.Data.(map[string]interface{})
			assert.Equal(t, float64(2), dataMap["success_count"], "应有2个设备成功绑定")
			assert.Equal(t, float64(0), dataMap["fail_count"], "应无失败")
		} else {
			t.Logf("Response data is nil: code=%d, message=%s", result.Code, result.Message)
		}

		var updatedDevice model.Device
		err = env.RawDB().Where("id = ?", devices[0].ID).First(&updatedDevice).Error
		require.NoError(t, err)
		assert.NotNil(t, updatedDevice.SeriesID)
		assert.Equal(t, series.ID, *updatedDevice.SeriesID)
	})

	t.Run("清除设备系列绑定-series_id=0", func(t *testing.T) {
		body := map[string]interface{}{
			"device_ids": []uint{devices[0].ID},
			"series_id":  0,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		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)

		var updatedDevice model.Device
		err = env.RawDB().Where("id = ?", devices[0].ID).First(&updatedDevice).Error
		require.NoError(t, err)
		assert.Nil(t, updatedDevice.SeriesID, "系列分配应被清除")
	})

	t.Run("批量设置-部分设备不存在", func(t *testing.T) {
		body := map[string]interface{}{
			"device_ids": []uint{devices[2].ID, 999999},
			"series_id":  series.ID,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		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)

		if result.Data != nil {
			dataMap := result.Data.(map[string]interface{})
			assert.Equal(t, float64(1), dataMap["success_count"], "应有1个设备成功")
			assert.Equal(t, float64(1), dataMap["fail_count"], "应有1个设备失败")

			if dataMap["failed_items"] != nil {
				failedItems := dataMap["failed_items"].([]interface{})
				assert.Len(t, failedItems, 1)
				failedItem := failedItems[0].(map[string]interface{})
				assert.Equal(t, float64(999999), failedItem["device_id"])
			}
		}
	})

	t.Run("设置不存在的系列分配-应失败", func(t *testing.T) {
		body := map[string]interface{}{
			"device_ids": []uint{devices[2].ID},
			"series_id":  999999,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		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, "不存在的系列分配应返回错误")
	})

	t.Run("设置禁用的系列-应失败", func(t *testing.T) {
		disabledSeries := createTestPackageSeries(t, env, "禁用系列")
		env.TX.Model(&model.PackageSeries{}).Where("id = ?", disabledSeries.ID).Update("status", constants.StatusDisabled)
		env.TX.Model(&model.ShopSeriesAllocation{}).Where("id = ?", disabledSeries.ID).Update("status", constants.StatusDisabled)

		body := map[string]interface{}{
			"device_ids": []uint{devices[2].ID},
			"series_id":  disabledSeries.ID,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		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, "禁用的系列分配应返回错误")
	})

	t.Run("代理商设置其他店铺的设备-应失败", func(t *testing.T) {
		otherShop := env.CreateTestShop("其他店铺", 1, nil)
		otherDevice := &model.Device{
			DeviceNo:    fmt.Sprintf("OTHER_%d", time.Now().UnixNano()),
			DeviceName:  "其他设备",
			DeviceType:  "router",
			MaxSimSlots: 4,
			Status:      constants.DeviceStatusInStock,
			ShopID:      &otherShop.ID,
		}
		require.NoError(t, env.TX.Create(otherDevice).Error)

		body := map[string]interface{}{
			"device_ids": []uint{otherDevice.ID},
			"series_id":  series.ID,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

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

		dataMap := result.Data.(map[string]interface{})
		assert.Equal(t, float64(0), dataMap["success_count"], "不应有成功")
		assert.Equal(t, float64(1), dataMap["fail_count"], "应全部失败")
	})

	t.Run("超级管理员可以设置任意店铺的设备", func(t *testing.T) {
		anotherShop := env.CreateTestShop("另一个店铺", 1, nil)
		anotherDevice := &model.Device{
			DeviceNo:    fmt.Sprintf("ADMIN_%d", time.Now().UnixNano()),
			DeviceName:  "管理员设备",
			DeviceType:  "router",
			MaxSimSlots: 4,
			Status:      constants.DeviceStatusInStock,
			ShopID:      &anotherShop.ID,
		}
		require.NoError(t, env.TX.Create(anotherDevice).Error)

		createTestAllocation(t, env, anotherShop.ID, series.ID, 0)

		body := map[string]interface{}{
			"device_ids": []uint{anotherDevice.ID},
			"series_id":  series.ID,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsSuperAdmin().Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		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, "超级管理员应能设置任意店铺的设备")

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

	t.Run("未认证请求应返回错误", func(t *testing.T) {
		body := map[string]interface{}{
			"device_ids": []uint{devices[0].ID},
			"series_id":  series.ID,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.ClearAuth().Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		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, "未认证请求应返回错误码")
	})

	t.Run("空设备ID列表-返回成功但无操作", func(t *testing.T) {
		body := map[string]interface{}{
			"device_ids": []uint{},
			"series_id":  series.ID,
		}
		jsonBody, _ := json.Marshal(body)

		resp, err := env.AsUser(agentAccount).Request("PATCH", "/api/admin/devices/series-binding", jsonBody)
		require.NoError(t, err)
		defer resp.Body.Close()

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

		assert.Equal(t, 0, result.Code, "当前实现：空列表返回成功")

		if result.Data != nil {
			dataMap := result.Data.(map[string]interface{})
			assert.Equal(t, float64(0), dataMap["success_count"], "空列表无成功项")
		}
	})
}
