package middleware

import (
	"context"
	"net/http"
	"strings"

	"tyc-server/app/main/api/internal/config"
	"tyc-server/app/main/model"
	jwtx "tyc-server/common/jwt"
	"tyc-server/common/result"
	"tyc-server/common/xerr"

	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/rest/httpx"
)

const (
	// 定义错误码
	AdminErrCodeUnauthorized = 401
)

type AdminAuthInterceptorMiddleware struct {
	Config config.Config
	// 注入model依赖
	AdminUserModel     model.AdminUserModel
	AdminUserRoleModel model.AdminUserRoleModel
	AdminRoleModel     model.AdminRoleModel
	AdminApiModel      model.AdminApiModel
	AdminRoleApiModel  model.AdminRoleApiModel
}

func NewAdminAuthInterceptorMiddleware(c config.Config,
	adminUserModel model.AdminUserModel,
	adminUserRoleModel model.AdminUserRoleModel,
	adminRoleModel model.AdminRoleModel,
	adminApiModel model.AdminApiModel,
	adminRoleApiModel model.AdminRoleApiModel) *AdminAuthInterceptorMiddleware {
	return &AdminAuthInterceptorMiddleware{
		Config:             c,
		AdminUserModel:     adminUserModel,
		AdminUserRoleModel: adminUserRoleModel,
		AdminRoleModel:     adminRoleModel,
		AdminApiModel:      adminApiModel,
		AdminRoleApiModel:  adminRoleApiModel,
	}
}

func (m *AdminAuthInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 1. JWT 校验
		claims, err := m.validateJWT(r)
		if err != nil {
			m.writeUnauthorizedResponse(w, err)
			return
		}

		// 2. 检查用户类型是否为管理员
		if claims.UserType != model.UserTypeAdmin {
			authErr := errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "用户类型错误，需要管理员权限")
			m.writeUnauthorizedResponse(w, authErr)
			return
		}

		// 3. 检查平台标识
		if claims.Platform != model.PlatformAdmin {
			authErr := errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "平台标识错误，需要管理员平台")
			m.writeUnauthorizedResponse(w, authErr)
			return
		}

		// 4. 将用户信息放入上下文
		ctx := context.WithValue(r.Context(), jwtx.ExtraKey, claims)
		r = r.WithContext(ctx)

		// 5. API 权限校验
		if err := m.validateApiPermission(r.Context(), claims.UserId, r.Method, r.URL.Path); err != nil {
			m.writeUnauthorizedResponse(w, err)
			return
		}

		// 6. 通过所有校验，继续处理请求
		next(w, r)
	}
}

// writeUnauthorizedResponse 写入401未授权响应
func (m *AdminAuthInterceptorMiddleware) writeUnauthorizedResponse(w http.ResponseWriter, err error) {
	errcode := xerr.TOKEN_EXPIRE_ERROR
	errmsg := xerr.MapErrMsg(errcode)

	// 从错误中提取错误码和错误消息
	causeErr := errors.Cause(err)
	if e, ok := causeErr.(*xerr.CodeError); ok {
		errcode = e.GetErrCode()
		errmsg = e.GetErrMsg()
	}

	// 返回401 HTTP状态码
	httpx.WriteJson(w, http.StatusUnauthorized, result.Error(errcode, errmsg))
}

// validateJWT 验证JWT token
func (m *AdminAuthInterceptorMiddleware) validateJWT(r *http.Request) (*jwtx.JwtClaims, error) {
	// 从请求头中获取Authorization字段
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "缺少Authorization头")
	}

	// 去掉Bearer前缀
	token := strings.TrimPrefix(authHeader, "Bearer ")
	if token == authHeader {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "Authorization头格式错误，缺少Bearer前缀")
	}

	claims, err := jwtx.ParseJwtToken(token, m.Config.AdminConfig.AccessSecret)
	if err != nil {
		// 根据错误类型返回不同的错误码
		errMsg := err.Error()
		if strings.Contains(errMsg, "token已过期") || strings.Contains(errMsg, "expired") {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "token解析失败: %v", err)
		}
		// 其他JWT解析错误使用统一的token过期错误码（更符合用户理解）
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "token解析失败: %v", err)
	}

	return claims, nil
}

// validateApiPermission 验证API权限
func (m *AdminAuthInterceptorMiddleware) validateApiPermission(ctx context.Context, userId int64, method, path string) error {
	// 1. 获取用户角色
	userRoles, err := m.getUserRoles(ctx, userId)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户角色失败: %v", err)
	}

	if len(userRoles) == 0 {
		return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户没有分配角色")
	}

	// 2. 检查是否为超级管理员
	if m.isSuperAdmin(ctx, userRoles) {
		// 超级管理员拥有所有权限，直接放行
		return nil
	}

	// 3. 获取当前请求的API信息
	api, err := m.getApiByMethodAndPath(ctx, method, path)
	if err != nil {
		// 如果API不存在，可能是公开接口，放行
		return nil
	}

	// 4. 检查用户角色是否有该API权限
	hasPermission, err := m.checkRoleApiPermission(ctx, userRoles, api.Id)
	if err != nil {
		return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查API权限失败: %v", err)
	}

	if !hasPermission {
		return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "权限不足，无法访问该接口")
	}

	return nil
}

// getUserRoles 获取用户角色
func (m *AdminAuthInterceptorMiddleware) getUserRoles(ctx context.Context, userId int64) ([]int64, error) {
	builder := m.AdminUserRoleModel.SelectBuilder().Where("user_id = ?", userId)
	userRoles, err := m.AdminUserRoleModel.FindAll(ctx, builder, "")
	if err != nil {
		return nil, err
	}

	var roleIds []int64
	for _, userRole := range userRoles {
		roleIds = append(roleIds, userRole.RoleId)
	}

	return roleIds, nil
}

// isSuperAdmin 检查是否为超级管理员
func (m *AdminAuthInterceptorMiddleware) isSuperAdmin(ctx context.Context, roleIds []int64) bool {
	// 检查是否有超级管理员角色
	for _, roleId := range roleIds {
		role, err := m.AdminRoleModel.FindOne(ctx, roleId)
		if err != nil {
			continue
		}
		// 检查是否为超级管理员角色
		if role.RoleCode == model.AdminRoleCodeSuper {
			return true
		}
	}
	return false
}

// getApiByMethodAndPath 根据方法和路径获取API信息
func (m *AdminAuthInterceptorMiddleware) getApiByMethodAndPath(ctx context.Context, method, path string) (*model.AdminApi, error) {
	builder := m.AdminApiModel.SelectBuilder().
		Where("method = ? AND url = ? AND status = ?", method, path, 1)

	apis, err := m.AdminApiModel.FindAll(ctx, builder, "")
	if err != nil {
		return nil, err
	}

	if len(apis) == 0 {
		return nil, errors.New("API不存在")
	}

	return apis[0], nil
}

// checkRoleApiPermission 检查角色是否有API权限
func (m *AdminAuthInterceptorMiddleware) checkRoleApiPermission(ctx context.Context, roleIds []int64, apiId int64) (bool, error) {
	for _, roleId := range roleIds {
		// 检查角色是否有该API权限
		_, err := m.AdminRoleApiModel.FindOneByRoleIdApiId(ctx, roleId, apiId)
		if err == nil {
			// 找到权限记录，说明有权限
			return true, nil
		}
		// 如果错误不是NotFound，说明是其他错误
		if !errors.Is(err, model.ErrNotFound) {
			return false, err
		}
	}

	return false, nil
}
