package middleware

import (
	"strconv"
	"strings"

	"git.ma-al.com/goc_daniel/b2b/app/config"
	"git.ma-al.com/goc_daniel/b2b/app/model"
	"git.ma-al.com/goc_daniel/b2b/app/service/authService"
	constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"

	"github.com/gofiber/fiber/v3"
)

// AuthMiddleware creates authentication middleware
func AuthMiddleware() fiber.Handler {
	authService := authService.NewAuthService()

	return func(c fiber.Ctx) error {
		// Get token from Authorization header
		authHeader := c.Get("Authorization")
		if authHeader == "" {
			// Try to get from cookie
			authHeader = c.Cookies("access_token")
			if authHeader == "" {
				return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
					"error": "authorization token required",
				})
			}
		} else {
			// Extract token from "Bearer <token>"
			parts := strings.Split(authHeader, " ")
			if len(parts) != 2 || parts[0] != "Bearer" {
				return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
					"error": "invalid authorization header format",
				})
			}
			authHeader = parts[1]
		}

		// Validate token
		claims, err := authService.ValidateToken(authHeader)
		if err != nil {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
				"error": "invalid or expired token",
			})
		}

		// Get user from database
		user, err := authService.GetUserByID(claims.UserID)
		if err != nil {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
				"error": "user not found",
			})
		}

		// Check if user is active
		if !user.IsActive {
			return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
				"error": "user account is inactive",
			})
		}

		// Create locale. LangID is overwritten by auth Token
		var userLocale model.UserLocale
		userLocale.OriginalUser = user

		// Check if target user is present
		targetUserIDAttribute := c.Query("target_user_id")

		if targetUserIDAttribute == "" {
			userLocale.User = user
			c.Locals(constdata.USER_LOCALE, &userLocale)

			return c.Next()
		}

		// We now populate the target user
		if model.CustomerRole(user.Role.Name) != model.RoleAdmin {
			return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
				"error": "admin access required",
			})
		}

		targetUserID, err := strconv.Atoi(targetUserIDAttribute)
		if err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
				"error": "invalid target user id attribute",
			})
		}

		// to verify target user, we use the same functionality as for verifying original user
		// Get target user from database
		user, err = authService.GetUserByID(uint(targetUserID))
		if err != nil {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
				"error": "target user not found",
			})
		}

		// Check if target user is active
		if !user.IsActive {
			return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
				"error": "target user account is inactive",
			})
		}

		userLocale.User = user
		c.Locals(constdata.USER_LOCALE, &userLocale)

		return c.Next()
	}
}

// RequireAdmin creates admin-only middleware
func RequireAdmin() fiber.Handler {
	return func(c fiber.Ctx) error {
		user := c.Locals("user")
		if user == nil {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
				"error": "not authenticated",
			})
		}

		userSession, ok := user.(*model.UserSession)
		if !ok {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
				"error": "invalid user session",
			})
		}

		if model.CustomerRole(userSession.RoleName) != model.RoleAdmin {
			return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
				"error": "admin access required",
			})
		}

		return c.Next()
	}
}

// GetConfig returns the app config
func GetConfig() *config.Config {
	return config.Get()
}
