package integration

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

	"github.com/gofiber/fiber/v2"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"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/errors"
	"github.com/break/junhong_cmp_fiber/pkg/response"
	"github.com/break/junhong_cmp_fiber/tests/testutils/integ"
)

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

	t.Run("成功创建权限", func(t *testing.T) {
		// 权限编码必须符合 module:action 格式（两边都以小写字母开头）
		permCode := fmt.Sprintf("test:action%d", time.Now().UnixNano())
		reqBody := dto.CreatePermissionRequest{
			PermName: fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
			PermCode: permCode,
			PermType: constants.PermissionTypeMenu,
			URL:      "/admin/users",
		}

		jsonBody, _ := json.Marshal(reqBody)
		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/permissions", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)

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

		var count int64
		env.RawDB().Model(&model.Permission{}).Where("perm_code = ?", permCode).Count(&count)
		assert.Equal(t, int64(1), count)
	})

	t.Run("权限编码重复时返回错误", func(t *testing.T) {
		existingPerm := env.CreateTestPermission(
			fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
			fmt.Sprintf("test:dup%d", time.Now().UnixNano()),
			constants.PermissionTypeMenu,
		)

		reqBody := dto.CreatePermissionRequest{
			PermName: fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
			PermCode: existingPerm.PermCode,
			PermType: constants.PermissionTypeMenu,
		}

		jsonBody, _ := json.Marshal(reqBody)
		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/permissions", jsonBody)
		require.NoError(t, err)

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

	t.Run("创建子权限", func(t *testing.T) {
		parentPermCode := fmt.Sprintf("test:parent%d", time.Now().UnixNano())
		parentPerm := env.CreateTestPermission(
			fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
			parentPermCode,
			constants.PermissionTypeMenu,
		)

		childPermCode := fmt.Sprintf("test:child%d", time.Now().UnixNano())
		reqBody := dto.CreatePermissionRequest{
			PermName: fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
			PermCode: childPermCode,
			PermType: constants.PermissionTypeButton,
			ParentID: &parentPerm.ID,
		}

		jsonBody, _ := json.Marshal(reqBody)
		resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/permissions", jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)

		var child model.Permission
		err = env.RawDB().Where("perm_code = ?", childPermCode).First(&child).Error
		require.NoError(t, err, "子权限应该已创建")
		require.NotNil(t, child.ParentID, "子权限的 ParentID 应该已设置")
		assert.Equal(t, parentPerm.ID, *child.ParentID)
	})
}

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

	testPerm := env.CreateTestPermission(
		fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		fmt.Sprintf("test:get%d", time.Now().UnixNano()),
		constants.PermissionTypeMenu,
	)

	t.Run("成功获取权限详情", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", fmt.Sprintf("/api/admin/permissions/%d", testPerm.ID), nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, 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/permissions/99999", nil)
		require.NoError(t, err)

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

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

	testPerm := env.CreateTestPermission(
		fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		fmt.Sprintf("test:upd%d", time.Now().UnixNano()),
		constants.PermissionTypeMenu,
	)

	t.Run("成功更新权限", func(t *testing.T) {
		newName := "更新后权限"
		reqBody := dto.UpdatePermissionRequest{
			PermName: &newName,
		}

		jsonBody, _ := json.Marshal(reqBody)
		resp, err := env.AsSuperAdmin().Request("PUT", fmt.Sprintf("/api/admin/permissions/%d", testPerm.ID), jsonBody)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)

		var updated model.Permission
		env.RawDB().First(&updated, testPerm.ID)
		assert.Equal(t, newName, updated.PermName)
	})
}

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

	t.Run("成功软删除权限", func(t *testing.T) {
		testPerm := env.CreateTestPermission(
			fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
			fmt.Sprintf("test:del%d", time.Now().UnixNano()),
			constants.PermissionTypeMenu,
		)

		resp, err := env.AsSuperAdmin().Request("DELETE", fmt.Sprintf("/api/admin/permissions/%d", testPerm.ID), nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)

		var deleted model.Permission
		err = env.RawDB().Unscoped().First(&deleted, testPerm.ID).Error
		require.NoError(t, err)
		assert.NotNil(t, deleted.DeletedAt)
	})
}

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

	for i := 1; i <= 5; i++ {
		env.CreateTestPermission(fmt.Sprintf("列表测试权限_%d", i), fmt.Sprintf("list:perm%d", i), constants.PermissionTypeMenu)
	}

	t.Run("成功获取权限列表", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/permissions?page=1&page_size=10", nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, 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/permissions?perm_type=%d", constants.PermissionTypeMenu), nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)
	})
}

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

	rootPerm := env.CreateTestPermission(
		fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		fmt.Sprintf("test:root%d", time.Now().UnixNano()),
		constants.PermissionTypeMenu,
	)

	childPermCode := fmt.Sprintf("test:child%d", time.Now().UnixNano())
	childPerm := &model.Permission{
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
		PermName:  fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:  childPermCode,
		PermType:  constants.PermissionTypeMenu,
		ParentID:  &rootPerm.ID,
		Status:    constants.StatusEnabled,
	}
	env.TX.Create(childPerm)

	grandchildPermCode := fmt.Sprintf("test:grand%d", time.Now().UnixNano())
	grandchildPerm := &model.Permission{
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
		PermName:  fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:  grandchildPermCode,
		PermType:  constants.PermissionTypeButton,
		ParentID:  &childPerm.ID,
		Status:    constants.StatusEnabled,
	}
	env.TX.Create(grandchildPerm)

	t.Run("成功获取权限树", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/permissions/tree", nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)

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

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

	platformPerm := &model.Permission{
		BaseModel:             model.BaseModel{Creator: 1, Updater: 1},
		PermName:              fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:              fmt.Sprintf("test:plat%d", time.Now().UnixNano()),
		PermType:              constants.PermissionTypeMenu,
		AvailableForRoleTypes: "1",
		Status:                constants.StatusEnabled,
	}
	env.TX.Create(platformPerm)

	customerPerm := &model.Permission{
		BaseModel:             model.BaseModel{Creator: 1, Updater: 1},
		PermName:              fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:              fmt.Sprintf("test:cust%d", time.Now().UnixNano()),
		PermType:              constants.PermissionTypeMenu,
		AvailableForRoleTypes: "2",
		Status:                constants.StatusEnabled,
	}
	env.TX.Create(customerPerm)

	commonPerm := &model.Permission{
		BaseModel:             model.BaseModel{Creator: 1, Updater: 1},
		PermName:              fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:              fmt.Sprintf("test:comm%d", time.Now().UnixNano()),
		PermType:              constants.PermissionTypeMenu,
		AvailableForRoleTypes: "1,2",
		Status:                constants.StatusEnabled,
	}
	env.TX.Create(commonPerm)

	t.Run("按角色类型过滤权限树-平台角色", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", fmt.Sprintf("/api/admin/permissions/tree?available_for_role_type=%d", constants.RoleTypePlatform), nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, 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/permissions/tree?available_for_role_type=2", nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, 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/permissions/tree?platform=all&available_for_role_type=1", nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)

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

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

	platformPerm := &model.Permission{
		BaseModel:             model.BaseModel{Creator: 1, Updater: 1},
		PermName:              fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:              fmt.Sprintf("test:fplat%d", time.Now().UnixNano()),
		PermType:              constants.PermissionTypeMenu,
		AvailableForRoleTypes: "1",
		Status:                constants.StatusEnabled,
	}
	env.TX.Create(platformPerm)

	customerPerm := &model.Permission{
		BaseModel:             model.BaseModel{Creator: 1, Updater: 1},
		PermName:              fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:              fmt.Sprintf("test:fcust%d", time.Now().UnixNano()),
		PermType:              constants.PermissionTypeMenu,
		AvailableForRoleTypes: "2",
		Status:                constants.StatusEnabled,
	}
	env.TX.Create(customerPerm)

	commonPerm := &model.Permission{
		BaseModel:             model.BaseModel{Creator: 1, Updater: 1},
		PermName:              fmt.Sprintf("test_permission_%d", time.Now().UnixNano()),
		PermCode:              fmt.Sprintf("test:fcomm%d", time.Now().UnixNano()),
		PermType:              constants.PermissionTypeMenu,
		AvailableForRoleTypes: "1,2",
		Status:                constants.StatusEnabled,
	}
	env.TX.Create(commonPerm)

	t.Run("过滤平台角色可用权限", func(t *testing.T) {
		resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/permissions?available_for_role_type=1", nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, 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/permissions/tree?available_for_role_type=%d", constants.RoleTypePlatform), nil)
		require.NoError(t, err)
		assert.Equal(t, fiber.StatusOK, resp.StatusCode)

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