package utils

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"os"
	"time"

	"git.ex.umbach.dev/LMS/libcore/models"
	"github.com/gofiber/fiber/v2"
	"github.com/rs/zerolog/log"
	"lms.de/backend/modules/config"
	"lms.de/backend/modules/database"
)

func GetXAuhorizationHeader(c *fiber.Ctx) string {
	// check if header is set
	if len(c.GetReqHeaders()[HeaderXAuthorization]) == 0 {
		return ""
	}

	return c.GetReqHeaders()[HeaderXAuthorization][0]
}

func GetXApiKeyHeader(c *fiber.Ctx) string {
	// check if header is set
	if len(c.GetReqHeaders()[HeaderXApiKey]) == 0 {
		return ""
	}

	return c.GetReqHeaders()[HeaderXApiKey][0]
}

func GetBrowserTabSessionHeader(c *fiber.Ctx) string {
	// check if header is set
	if len(c.GetReqHeaders()[HeaderBrowserTabSession]) == 0 {
		return ""
	}

	return c.GetReqHeaders()[HeaderBrowserTabSession][0]
}

func GetSessionExpiresAtTime() time.Time {
	return time.Now().Add(time.Second * SessionExpiresAtTime)
}

func IsPasswordLengthValid(password string) bool {
	lenPassword := len(password)

	if lenPassword < MinPassword || lenPassword > MaxPassword {
		log.Error().Msg("Password length not valid")
		return false
	}

	return true
}

// generates a random subdomain and check if it is already in use
func GenerateSubdomain() string {
	var subdomain string
	var err error

	for {
		subdomain, err = GenerateCode(6)

		if err != nil {
			log.Error().Msg("Failed to generate subdomain")
			return ""
		}

		if !IsSubdomainAlreadyInUse(subdomain) {
			break
		}

		log.Info().Msg("Subdomain already in use, generating new one")
	}

	return subdomain
}

func IsSubdomainAlreadyInUse(subdomain string) bool {
	var organization models.Organization

	if err := database.DB.Where("subdomain = ?", subdomain).First(&organization).Error; err != nil {
		return false
	}

	return true
}

func GenerateCode(codeLength int) (string, error) {
	var letters = "abcdefghijklmnopqrstuvwxyz"

	r := make([]byte, codeLength)

	for i := 0; i < codeLength; i++ {
		num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))

		if err != nil {
			log.Error().Msgf("Failed to session: %v", err)
			return "", err
		}

		r[i] = letters[num.Int64()]
	}

	return string(r), nil
}

func IsFileTypeAllowed(contentType string, allowedContentTypes []string) bool {
	for _, aType := range allowedContentTypes {
		if aType == contentType {
			return true
		}
	}

	return false
}

func DeleteFile(filePath string) {
	err := os.Remove(config.Cfg.FolderPaths.PublicStatic + filePath)

	if err != nil {
		log.Error().Msgf("Failed to delete file: %v", err)
	}
}

func CreateFolderStructureIfNotExists(folderPath string) {
	if _, err := os.Stat(folderPath); os.IsNotExist(err) {
		if err := os.MkdirAll(folderPath, os.ModePerm); err != nil {
			log.Error().Msgf("Failed to create folder structure, err: %v", err)
		}
	}
}

// GetFullImagePath returns the database path and the public path for the image
func GetFullImagePath(organizationId string, lessonId string) (databasePath string, publicPath string) {
	if lessonId == "" {
		return fmt.Sprintf(
				"o/%s/", organizationId),
			fmt.Sprintf(
				"%s/o/%s/", config.Cfg.FolderPaths.PublicStatic, organizationId)
	}

	return fmt.Sprintf(
			"o/%s/l/%s/", organizationId, lessonId),
		fmt.Sprintf(
			"%s/o/%s/l/%s/", config.Cfg.FolderPaths.PublicStatic, organizationId, lessonId)
}
