package packagepkg

import (
	"context"
	"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/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func generateUniquePackageCode(prefix string) string {
	return fmt.Sprintf("%s_%d", prefix, time.Now().UnixNano())
}

func TestPackageService_Create(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	t.Run("创建成功", func(t *testing.T) {
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_CREATE"),
			PackageName:    "创建测试套餐",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}

		resp, err := svc.Create(ctx, req)
		require.NoError(t, err)
		assert.NotZero(t, resp.ID)
		assert.Equal(t, req.PackageCode, resp.PackageCode)
		assert.Equal(t, req.PackageName, resp.PackageName)
		assert.Equal(t, constants.StatusEnabled, resp.Status)
		assert.Equal(t, 2, resp.ShelfStatus)
	})

	t.Run("编码重复失败", func(t *testing.T) {
		code := generateUniquePackageCode("PKG_DUP")
		req1 := &dto.CreatePackageRequest{
			PackageCode:    code,
			PackageName:    "第一个套餐",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		_, err := svc.Create(ctx, req1)
		require.NoError(t, err)

		req2 := &dto.CreatePackageRequest{
			PackageCode:    code,
			PackageName:    "第二个套餐",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		_, err = svc.Create(ctx, req2)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeConflict, appErr.Code)
	})

	t.Run("系列不存在失败", func(t *testing.T) {
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_SERIES"),
			PackageName:    "系列测试套餐",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
			SeriesID:       func() *uint { id := uint(99999); return &id }(),
		}

		_, err := svc.Create(ctx, req)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})
}

func TestPackageService_UpdateStatus(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	req := &dto.CreatePackageRequest{
		PackageCode:    generateUniquePackageCode("PKG_STATUS"),
		PackageName:    "状态测试套餐",
		PackageType:    "formal",
		DurationMonths: 1,
		Price:          9900,
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)

	t.Run("禁用套餐时自动强制下架", func(t *testing.T) {
		err := svc.UpdateShelfStatus(ctx, created.ID, 1)
		require.NoError(t, err)

		pkg, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, 1, pkg.ShelfStatus)

		err = svc.UpdateStatus(ctx, created.ID, constants.StatusDisabled)
		require.NoError(t, err)

		pkg, err = svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusDisabled, pkg.Status)
		assert.Equal(t, 2, pkg.ShelfStatus)
	})

	t.Run("启用套餐时保持原上架状态", func(t *testing.T) {
		req2 := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_ENABLE"),
			PackageName:    "启用测试套餐",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		created2, err := svc.Create(ctx, req2)
		require.NoError(t, err)

		err = svc.UpdateShelfStatus(ctx, created2.ID, 1)
		require.NoError(t, err)

		err = svc.UpdateStatus(ctx, created2.ID, constants.StatusDisabled)
		require.NoError(t, err)

		pkg, err := svc.Get(ctx, created2.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusDisabled, pkg.Status)
		assert.Equal(t, 2, pkg.ShelfStatus)

		err = svc.UpdateStatus(ctx, created2.ID, constants.StatusEnabled)
		require.NoError(t, err)

		pkg, err = svc.Get(ctx, created2.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusEnabled, pkg.Status)
		assert.Equal(t, 2, pkg.ShelfStatus)
	})
}

func TestPackageService_UpdateShelfStatus(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	t.Run("启用状态的套餐可以上架", func(t *testing.T) {
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_SHELF_ENABLE"),
			PackageName:    "上架测试-启用",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		created, err := svc.Create(ctx, req)
		require.NoError(t, err)

		pkg, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, 1, pkg.Status)
		assert.Equal(t, 2, pkg.ShelfStatus)

		err = svc.UpdateShelfStatus(ctx, created.ID, 1)
		require.NoError(t, err)

		pkg, err = svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, 1, pkg.ShelfStatus)
	})

	t.Run("禁用状态的套餐不能上架", func(t *testing.T) {
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_SHELF_DISABLE"),
			PackageName:    "上架测试-禁用",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		created, err := svc.Create(ctx, req)
		require.NoError(t, err)

		err = svc.UpdateStatus(ctx, created.ID, constants.StatusDisabled)
		require.NoError(t, err)

		err = svc.UpdateShelfStatus(ctx, created.ID, 1)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidStatus, appErr.Code)

		pkg, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, 2, pkg.ShelfStatus)
	})

	t.Run("下架成功", func(t *testing.T) {
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_SHELF_OFF"),
			PackageName:    "下架测试",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		created, err := svc.Create(ctx, req)
		require.NoError(t, err)

		err = svc.UpdateShelfStatus(ctx, created.ID, 1)
		require.NoError(t, err)

		pkg, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, 1, pkg.ShelfStatus)

		err = svc.UpdateShelfStatus(ctx, created.ID, 2)
		require.NoError(t, err)

		pkg, err = svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, 2, pkg.ShelfStatus)
	})
}

func TestPackageService_Get(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	req := &dto.CreatePackageRequest{
		PackageCode:    generateUniquePackageCode("PKG_GET"),
		PackageName:    "查询测试套餐",
		PackageType:    "formal",
		DurationMonths: 1,
		Price:          9900,
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)

	t.Run("获取成功", func(t *testing.T) {
		resp, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, created.PackageCode, resp.PackageCode)
		assert.Equal(t, created.PackageName, resp.PackageName)
		assert.Equal(t, created.ID, resp.ID)
	})

	t.Run("不存在返回错误", func(t *testing.T) {
		_, err := svc.Get(ctx, 99999)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})
}

func TestPackageService_Update(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	req := &dto.CreatePackageRequest{
		PackageCode:    generateUniquePackageCode("PKG_UPDATE"),
		PackageName:    "更新测试套餐",
		PackageType:    "formal",
		DurationMonths: 1,
		Price:          9900,
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)

	t.Run("更新成功", func(t *testing.T) {
		newName := "更新后的套餐名称"
		newPrice := int64(19900)
		updateReq := &dto.UpdatePackageRequest{
			PackageName: &newName,
			Price:       &newPrice,
		}

		resp, err := svc.Update(ctx, created.ID, updateReq)
		require.NoError(t, err)
		assert.Equal(t, newName, resp.PackageName)
		assert.Equal(t, newPrice, resp.Price)
	})

	t.Run("更新不存在的套餐", func(t *testing.T) {
		newName := "test"
		updateReq := &dto.UpdatePackageRequest{
			PackageName: &newName,
		}

		_, err := svc.Update(ctx, 99999, updateReq)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})
}

func TestPackageService_Delete(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	req := &dto.CreatePackageRequest{
		PackageCode:    generateUniquePackageCode("PKG_DELETE"),
		PackageName:    "删除测试套餐",
		PackageType:    "formal",
		DurationMonths: 1,
		Price:          9900,
	}
	created, err := svc.Create(ctx, req)
	require.NoError(t, err)

	t.Run("删除成功", func(t *testing.T) {
		err := svc.Delete(ctx, created.ID)
		require.NoError(t, err)

		_, err = svc.Get(ctx, created.ID)
		require.Error(t, err)
	})

	t.Run("删除不存在的套餐", func(t *testing.T) {
		err := svc.Delete(ctx, 99999)
		require.Error(t, err)
	})
}

func TestPackageService_List(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	packages := []dto.CreatePackageRequest{
		{
			PackageCode:    generateUniquePackageCode("PKG_LIST_001"),
			PackageName:    "列表测试套餐1",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		},
		{
			PackageCode:    generateUniquePackageCode("PKG_LIST_002"),
			PackageName:    "列表测试套餐2",
			PackageType:    "addon",
			DurationMonths: 1,
			Price:          4900,
		},
		{
			PackageCode:    generateUniquePackageCode("PKG_LIST_003"),
			PackageName:    "列表测试套餐3",
			PackageType:    "formal",
			DurationMonths: 12,
			Price:          99900,
		},
	}

	for _, p := range packages {
		_, err := svc.Create(ctx, &p)
		require.NoError(t, err)
	}

	t.Run("列表查询", func(t *testing.T) {
		req := &dto.PackageListRequest{
			Page:     1,
			PageSize: 10,
		}

		resp, total, err := svc.List(ctx, req)
		require.NoError(t, err)
		assert.Greater(t, total, int64(0))
		assert.Greater(t, len(resp), 0)
	})

	t.Run("按套餐类型过滤", func(t *testing.T) {
		packageType := "formal"
		req := &dto.PackageListRequest{
			Page:        1,
			PageSize:    10,
			PackageType: &packageType,
		}

		resp, _, err := svc.List(ctx, req)
		require.NoError(t, err)
		for _, p := range resp {
			assert.Equal(t, packageType, p.PackageType)
		}
	})

	t.Run("按状态过滤", func(t *testing.T) {
		status := constants.StatusEnabled
		req := &dto.PackageListRequest{
			Page:     1,
			PageSize: 10,
			Status:   &status,
		}

		resp, _, err := svc.List(ctx, req)
		require.NoError(t, err)
		for _, p := range resp {
			assert.Equal(t, status, p.Status)
		}
	})
}

func TestPackageService_SeriesNameInResponse(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	packageStore := postgres.NewPackageStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	svc := New(packageStore, packageSeriesStore, nil, nil)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

	// 创建套餐系列
	series := &model.PackageSeries{
		SeriesCode:  fmt.Sprintf("SERIES_%d", time.Now().UnixNano()),
		SeriesName:  "测试套餐系列",
		Description: "用于测试系列名称字段",
		Status:      constants.StatusEnabled,
	}
	series.Creator = 1
	err := packageSeriesStore.Create(ctx, series)
	require.NoError(t, err)

	t.Run("创建套餐时返回系列名称", func(t *testing.T) {
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_SERIES"),
			PackageName:    "带系列的套餐",
			SeriesID:       &series.ID,
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}

		resp, err := svc.Create(ctx, req)
		require.NoError(t, err)
		assert.NotNil(t, resp.SeriesName)
		assert.Equal(t, series.SeriesName, *resp.SeriesName)
	})

	t.Run("获取套餐时返回系列名称", func(t *testing.T) {
		// 先创建一个套餐
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_GET_SERIES"),
			PackageName:    "获取测试套餐",
			SeriesID:       &series.ID,
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		created, err := svc.Create(ctx, req)
		require.NoError(t, err)

		// 获取套餐
		resp, err := svc.Get(ctx, created.ID)
		require.NoError(t, err)
		assert.NotNil(t, resp.SeriesName)
		assert.Equal(t, series.SeriesName, *resp.SeriesName)
	})

	t.Run("更新套餐时返回系列名称", func(t *testing.T) {
		// 先创建一个套餐
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_UPDATE_SERIES"),
			PackageName:    "更新测试套餐",
			SeriesID:       &series.ID,
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}
		created, err := svc.Create(ctx, req)
		require.NoError(t, err)

		// 更新套餐
		newName := "更新后的套餐"
		updateReq := &dto.UpdatePackageRequest{
			PackageName: &newName,
		}
		resp, err := svc.Update(ctx, created.ID, updateReq)
		require.NoError(t, err)
		assert.NotNil(t, resp.SeriesName)
		assert.Equal(t, series.SeriesName, *resp.SeriesName)
	})

	t.Run("列表查询时返回系列名称", func(t *testing.T) {
		// 创建多个带系列的套餐
		for i := 0; i < 3; i++ {
			req := &dto.CreatePackageRequest{
				PackageCode:    generateUniquePackageCode(fmt.Sprintf("PKG_LIST_SERIES_%d", i)),
				PackageName:    fmt.Sprintf("列表测试套餐%d", i),
				SeriesID:       &series.ID,
				PackageType:    "formal",
				DurationMonths: 1,
				Price:          9900,
			}
			_, err := svc.Create(ctx, req)
			require.NoError(t, err)
		}

		// 查询列表
		listReq := &dto.PackageListRequest{
			Page:     1,
			PageSize: 10,
			SeriesID: &series.ID,
		}
		resp, _, err := svc.List(ctx, listReq)
		require.NoError(t, err)
		assert.Greater(t, len(resp), 0)

		// 验证所有套餐都有系列名称
		for _, pkg := range resp {
			if pkg.SeriesID != nil && *pkg.SeriesID == series.ID {
				assert.NotNil(t, pkg.SeriesName)
				assert.Equal(t, series.SeriesName, *pkg.SeriesName)
			}
		}
	})

	t.Run("没有系列的套餐SeriesName为空", func(t *testing.T) {
		req := &dto.CreatePackageRequest{
			PackageCode:    generateUniquePackageCode("PKG_NO_SERIES"),
			PackageName:    "无系列套餐",
			PackageType:    "formal",
			DurationMonths: 1,
			Price:          9900,
		}

		resp, err := svc.Create(ctx, req)
		require.NoError(t, err)
		assert.Nil(t, resp.SeriesID)
		assert.Nil(t, resp.SeriesName)
	})
}
