package integration

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

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	pkgGorm "github.com/break/junhong_cmp_fiber/pkg/gorm"
	"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"
)

// ==================== Part 1: 套餐系列 API 测试 ====================

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

	timestamp := time.Now().Unix()
	seriesCode := fmt.Sprintf("TEST_SERIES_%d", timestamp)

	body := map[string]interface{}{
		"series_code": seriesCode,
		"series_name": "测试套餐系列",
		"description": "API集成测试创建的套餐系列",
	}
	jsonBody, _ := json.Marshal(body)

	resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/package-series", 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, ok := result.Data.(map[string]interface{})
	require.True(t, ok)
	assert.Equal(t, seriesCode, dataMap["series_code"])
	assert.Equal(t, "测试套餐系列", dataMap["series_name"])
	assert.Equal(t, float64(constants.StatusEnabled), dataMap["status"])

	t.Logf("创建的套餐系列 ID: %v", dataMap["id"])
}

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

	timestamp := time.Now().Unix()
	seriesCode := fmt.Sprintf("TEST_SERIES_%d", timestamp)

	series := &model.PackageSeries{
		SeriesCode:  seriesCode,
		SeriesName:  "测试套餐系列",
		Description: "测试描述",
		Status:      constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
		},
	}
	require.NoError(t, env.TX.Create(series).Error)

	url := fmt.Sprintf("/api/admin/package-series/%d", series.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 := result.Data.(map[string]interface{})
	assert.Equal(t, seriesCode, dataMap["series_code"])
	assert.Equal(t, "测试套餐系列", dataMap["series_name"])
}

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

	timestamp := time.Now().Unix()
	seriesList := []*model.PackageSeries{
		{
			SeriesCode: fmt.Sprintf("TEST_LIST_%d_001", timestamp),
			SeriesName: "列表测试系列1",
			Status:     constants.StatusEnabled,
			BaseModel:  model.BaseModel{Creator: 1},
		},
		{
			SeriesCode: fmt.Sprintf("TEST_LIST_%d_002", timestamp),
			SeriesName: "列表测试系列2",
			Status:     constants.StatusEnabled,
			BaseModel:  model.BaseModel{Creator: 1},
		},
	}
	for _, s := range seriesList {
		require.NoError(t, env.TX.Create(s).Error)
	}

	resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/package-series?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)
}

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

	timestamp := time.Now().Unix()
	seriesCode := fmt.Sprintf("TEST_SERIES_%d", timestamp)

	series := &model.PackageSeries{
		SeriesCode:  seriesCode,
		SeriesName:  "原始系列名称",
		Description: "原始描述",
		Status:      constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
		},
	}
	require.NoError(t, env.TX.Create(series).Error)

	body := map[string]interface{}{
		"series_name": "更新后的系列名称",
		"description": "更新后的描述",
	}
	jsonBody, _ := json.Marshal(body)

	url := fmt.Sprintf("/api/admin/package-series/%d", series.ID)
	resp, err := env.AsSuperAdmin().Request("PUT", url, 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, "更新后的系列名称", dataMap["series_name"])
	assert.Equal(t, "更新后的描述", dataMap["description"])
}

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

	timestamp := time.Now().Unix()
	seriesCode := fmt.Sprintf("TEST_SERIES_%d", timestamp)

	series := &model.PackageSeries{
		SeriesCode: seriesCode,
		SeriesName: "测试系列",
		Status:     constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
		},
	}
	require.NoError(t, env.TX.Create(series).Error)

	body := map[string]interface{}{
		"status": constants.StatusDisabled,
	}
	jsonBody, _ := json.Marshal(body)

	url := fmt.Sprintf("/api/admin/package-series/%d/status", series.ID)
	resp, err := env.AsSuperAdmin().Request("PATCH", url, 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 updatedSeries model.PackageSeries
	env.RawDB().First(&updatedSeries, series.ID)
	assert.Equal(t, constants.StatusDisabled, updatedSeries.Status)
}

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

	timestamp := time.Now().Unix()
	seriesCode := fmt.Sprintf("TEST_SERIES_%d", timestamp)

	series := &model.PackageSeries{
		SeriesCode: seriesCode,
		SeriesName: "测试系列",
		Status:     constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
		},
	}
	require.NoError(t, env.TX.Create(series).Error)

	url := fmt.Sprintf("/api/admin/package-series/%d", series.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 deletedSeries model.PackageSeries
	err = env.RawDB().First(&deletedSeries, series.ID).Error
	assert.Error(t, err, "删除后应查不到套餐系列")
}

// ==================== Part 2: 套餐 API 测试 ====================

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

	timestamp := time.Now().Unix()
	packageCode := fmt.Sprintf("TEST_PKG_%d", timestamp)

	body := map[string]interface{}{
		"package_code":    packageCode,
		"package_name":    "测试套餐",
		"package_type":    "formal",
		"duration_months": 12,
		"price":           99900,
		"data_type":       "real",
		"real_data_mb":    10240,
	}
	jsonBody, _ := json.Marshal(body)

	resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/packages", 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, ok := result.Data.(map[string]interface{})
	require.True(t, ok)
	assert.Equal(t, packageCode, dataMap["package_code"])
	assert.Equal(t, "测试套餐", dataMap["package_name"])
	assert.Equal(t, float64(constants.StatusEnabled), dataMap["status"])
	assert.Equal(t, float64(2), dataMap["shelf_status"]) // 默认下架

	t.Logf("创建的套餐 ID: %v", dataMap["id"])
}

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

	timestamp := time.Now().Unix()
	packageCode := fmt.Sprintf("TEST_PKG_%d", timestamp)

	// 先创建套餐
	createBody := map[string]interface{}{
		"package_code":    packageCode,
		"package_name":    "测试套餐",
		"package_type":    "formal",
		"duration_months": 12,
		"price":           99900,
	}
	jsonBody, _ := json.Marshal(createBody)

	createResp, err := env.AsSuperAdmin().Request("POST", "/api/admin/packages", jsonBody)
	require.NoError(t, err)
	defer createResp.Body.Close()

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

	dataMap := createResult.Data.(map[string]interface{})
	pkgID := uint(dataMap["id"].(float64))

	// 先上架套餐
	shelfBody := map[string]interface{}{
		"shelf_status": 1,
	}
	shelfJsonBody, _ := json.Marshal(shelfBody)

	shelfResp, err := env.AsSuperAdmin().Request("PATCH", fmt.Sprintf("/api/admin/packages/%d/shelf", pkgID), shelfJsonBody)
	require.NoError(t, err)
	defer shelfResp.Body.Close()

	// 禁用套餐
	disableBody := map[string]interface{}{
		"status": constants.StatusDisabled,
	}
	disableJsonBody, _ := json.Marshal(disableBody)

	disableResp, err := env.AsSuperAdmin().Request("PATCH", fmt.Sprintf("/api/admin/packages/%d/status", pkgID), disableJsonBody)
	require.NoError(t, err)
	defer disableResp.Body.Close()

	var disableResult response.Response
	err = json.NewDecoder(disableResp.Body).Decode(&disableResult)
	require.NoError(t, err)
	t.Logf("禁用响应: 状态码=%d, 错误码=%d, 消息=%s", disableResp.StatusCode, disableResult.Code, disableResult.Message)
	require.Equal(t, 200, disableResp.StatusCode, "禁用套餐应该成功")
	require.Equal(t, 0, disableResult.Code, "禁用套餐应该返回成功")

	// 验证禁用后自动下架
	var updatedPkg model.Package
	ctx := pkgGorm.SkipDataPermission(context.Background())
	require.NoError(t, env.RawDB().WithContext(ctx).First(&updatedPkg, pkgID).Error)
	assert.Equal(t, constants.StatusDisabled, updatedPkg.Status, "套餐应该被禁用")
	assert.Equal(t, 2, updatedPkg.ShelfStatus, "禁用时应该强制下架")

	t.Logf("禁用套餐后，状态: %d, 上架状态: %d", updatedPkg.Status, updatedPkg.ShelfStatus)
}

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

	timestamp := time.Now().Unix()
	packageCode := fmt.Sprintf("TEST_PKG_%d", timestamp)

	// 先创建套餐
	createBody := map[string]interface{}{
		"package_code":    packageCode,
		"package_name":    "测试套餐",
		"package_type":    "formal",
		"duration_months": 12,
		"price":           99900,
	}
	jsonBody, _ := json.Marshal(createBody)

	createResp, err := env.AsSuperAdmin().Request("POST", "/api/admin/packages", jsonBody)
	require.NoError(t, err)
	defer createResp.Body.Close()

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

	dataMap := createResult.Data.(map[string]interface{})
	pkgID := uint(dataMap["id"].(float64))

	// 禁用套餐
	disableBody := map[string]interface{}{
		"status": constants.StatusDisabled,
	}
	disableJsonBody, _ := json.Marshal(disableBody)

	disableResp, err := env.AsSuperAdmin().Request("PATCH", fmt.Sprintf("/api/admin/packages/%d/status", pkgID), disableJsonBody)
	require.NoError(t, err)
	defer disableResp.Body.Close()

	var disableResult response.Response
	err = json.NewDecoder(disableResp.Body).Decode(&disableResult)
	require.NoError(t, err)
	t.Logf("禁用响应: 状态码=%d, 错误码=%d, 消息=%s", disableResp.StatusCode, disableResult.Code, disableResult.Message)
	require.Equal(t, 200, disableResp.StatusCode, "禁用套餐应该成功")
	require.Equal(t, 0, disableResult.Code, "禁用套餐应该返回成功")

	// 尝试上架禁用的套餐
	shelfBody := map[string]interface{}{
		"shelf_status": 1,
	}
	shelfJsonBody, _ := json.Marshal(shelfBody)

	shelfResp, err := env.AsSuperAdmin().Request("PATCH", fmt.Sprintf("/api/admin/packages/%d/shelf", pkgID), shelfJsonBody)
	require.NoError(t, err)
	defer shelfResp.Body.Close()

	// 应该返回错误
	var result response.Response
	err = json.NewDecoder(shelfResp.Body).Decode(&result)
	require.NoError(t, err)
	assert.NotEqual(t, 0, result.Code, "禁用的套餐不能上架，应返回错误码")

	// 验证套餐仍然是下架状态
	var unchangedPkg model.Package
	ctx := pkgGorm.SkipDataPermission(context.Background())
	require.NoError(t, env.RawDB().WithContext(ctx).First(&unchangedPkg, pkgID).Error)
	assert.Equal(t, 2, unchangedPkg.ShelfStatus, "禁用的套餐应该保持下架状态")

	t.Logf("尝试上架禁用套餐失败，错误码: %d, 消息: %s", result.Code, result.Message)
}

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

	timestamp := time.Now().Unix()
	packageCode := fmt.Sprintf("TEST_PKG_%d", timestamp)

	pkg := &model.Package{
		PackageCode:    packageCode,
		PackageName:    "测试套餐",
		PackageType:    "formal",
		DurationMonths: 12,
		Price:          99900,
		Status:         constants.StatusEnabled,
		ShelfStatus:    2,
		BaseModel: model.BaseModel{
			Creator: 1,
		},
	}
	require.NoError(t, env.TX.Create(pkg).Error)

	url := fmt.Sprintf("/api/admin/packages/%d", pkg.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 := result.Data.(map[string]interface{})
	assert.Equal(t, packageCode, dataMap["package_code"])
	assert.Equal(t, "测试套餐", dataMap["package_name"])
}

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

	timestamp := time.Now().Unix()
	pkgList := []*model.Package{
		{
			PackageCode:    fmt.Sprintf("TEST_LIST_%d_001", timestamp),
			PackageName:    "列表测试套餐1",
			PackageType:    "formal",
			DurationMonths: 12,
			Price:          99900,
			Status:         constants.StatusEnabled,
			ShelfStatus:    1,
			BaseModel:      model.BaseModel{Creator: 1},
		},
		{
			PackageCode:    fmt.Sprintf("TEST_LIST_%d_002", timestamp),
			PackageName:    "列表测试套餐2",
			PackageType:    "addon",
			DurationMonths: 1,
			Price:          9990,
			Status:         constants.StatusEnabled,
			ShelfStatus:    2,
			BaseModel:      model.BaseModel{Creator: 1},
		},
	}
	for _, p := range pkgList {
		require.NoError(t, env.TX.Create(p).Error)
	}

	resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/packages?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)
}

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

	timestamp := time.Now().Unix()
	packageCode := fmt.Sprintf("TEST_PKG_%d", timestamp)

	pkg := &model.Package{
		PackageCode:    packageCode,
		PackageName:    "原始套餐名称",
		PackageType:    "formal",
		DurationMonths: 12,
		Price:          99900,
		Status:         constants.StatusEnabled,
		ShelfStatus:    2,
		BaseModel: model.BaseModel{
			Creator: 1,
		},
	}
	require.NoError(t, env.TX.Create(pkg).Error)

	body := map[string]interface{}{
		"package_name": "更新后的套餐名称",
		"price":        119900,
	}
	jsonBody, _ := json.Marshal(body)

	url := fmt.Sprintf("/api/admin/packages/%d", pkg.ID)
	resp, err := env.AsSuperAdmin().Request("PUT", url, 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, "更新后的套餐名称", dataMap["package_name"])
	assert.Equal(t, float64(119900), dataMap["price"])
}

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

	timestamp := time.Now().Unix()
	packageCode := fmt.Sprintf("TEST_PKG_%d", timestamp)

	pkg := &model.Package{
		PackageCode:    packageCode,
		PackageName:    "测试套餐",
		PackageType:    "formal",
		DurationMonths: 12,
		Price:          99900,
		Status:         constants.StatusEnabled,
		ShelfStatus:    2,
		BaseModel: model.BaseModel{
			Creator: 1,
		},
	}
	require.NoError(t, env.TX.Create(pkg).Error)

	url := fmt.Sprintf("/api/admin/packages/%d", pkg.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 deletedPkg model.Package
	err = env.RawDB().First(&deletedPkg, pkg.ID).Error
	assert.Error(t, err, "删除后应查不到套餐")
}
