package middleware

import (
	"strings"

	"github.com/break/junhong_cmp_fiber/pkg/auth"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/gofiber/fiber/v2"
	"go.uber.org/zap"
)

// PersonalAuthMiddleware 个人客户认证中间件
type PersonalAuthMiddleware struct {
	jwtManager *auth.JWTManager
	logger     *zap.Logger
}

// NewPersonalAuthMiddleware 创建个人客户认证中间件
func NewPersonalAuthMiddleware(jwtManager *auth.JWTManager, logger *zap.Logger) *PersonalAuthMiddleware {
	return &PersonalAuthMiddleware{
		jwtManager: jwtManager,
		logger:     logger,
	}
}

// Authenticate 认证中间件
func (m *PersonalAuthMiddleware) Authenticate() fiber.Handler {
	return func(c *fiber.Ctx) error {
		// 从 Authorization header 获取 token
		authHeader := c.Get("Authorization")
		if authHeader == "" {
			m.logger.Warn("个人客户认证失败：缺少 Authorization header",
				zap.String("path", c.Path()),
				zap.String("method", c.Method()),
			)
			return errors.New(errors.CodeUnauthorized, "未提供认证令牌")
		}

		// 检查 Bearer 前缀
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 || parts[0] != "Bearer" {
			m.logger.Warn("个人客户认证失败：Authorization header 格式错误",
				zap.String("path", c.Path()),
				zap.String("auth_header", authHeader),
			)
			return errors.New(errors.CodeUnauthorized, "认证令牌格式错误")
		}

		token := parts[1]

		// 验证 token
		claims, err := m.jwtManager.VerifyPersonalCustomerToken(token)
		if err != nil {
			m.logger.Warn("个人客户认证失败：token 验证失败",
				zap.String("path", c.Path()),
				zap.Error(err),
			)
			return errors.New(errors.CodeUnauthorized, "认证令牌无效或已过期")
		}

		// 将客户信息存储到 context 中
		c.Locals("customer_id", claims.CustomerID)
		c.Locals("customer_phone", claims.Phone)

		// 设置 SkipOwnerFilter 标记，跳过 B 端数据权限过滤
		// 个人客户不参与 RBAC 权限体系，不需要 Owner 过滤
		c.Locals("skip_owner_filter", true)

		m.logger.Debug("个人客户认证成功",
			zap.Uint("customer_id", claims.CustomerID),
			zap.String("phone", claims.Phone),
			zap.String("path", c.Path()),
		)

		return c.Next()
	}
}

// GetCustomerID 从 context 中获取当前个人客户 ID
func GetCustomerID(c *fiber.Ctx) (uint, bool) {
	customerID, ok := c.Locals("customer_id").(uint)
	return customerID, ok
}

// GetCustomerPhone 从 context 中获取当前个人客户手机号
func GetCustomerPhone(c *fiber.Ctx) (string, bool) {
	phone, ok := c.Locals("customer_phone").(string)
	return phone, ok
}
