package organization

import (
	"encoding/base64"
	"time"

	"git.ex.umbach.dev/Alex/roese-utils/rslogger"
	"git.ex.umbach.dev/Alex/roese-utils/rsutils"
	"git.ex.umbach.dev/LMS/libcore/models"
	"github.com/gofiber/fiber/v2"
	"github.com/google/uuid"
	"github.com/rs/zerolog/log"
	"golang.org/x/crypto/bcrypt"
	"lms.de/backend/modules/database"
	"lms.de/backend/modules/logger"
	"lms.de/backend/modules/structs"
	"lms.de/backend/modules/utils"
)

func CreateOrganization(c *fiber.Ctx) error {
	// swagger:operation POST /organization organization createOrganization
	// ---
	// summary: Create organization
	// consumes:
	// - application/json
	// produces:
	// - application/json
	// parameters:
	// - name: body
	//   in: body
	//   schema:
	//     "$ref": "#/definitions/CreateOrganizationRequest"
	// responses:
	//   '200':
	//     description: Organization created successfully
	//     schema:
	//       "$ref": "#/definitions/CreateOrganizationResponse"
	//   '400':
	//     description: Invalid request body
	//   '500':
	//     description: Failed to create organization

	var body structs.CreateOrganizationRequest

	if err := rsutils.BodyParserHelper(c, &body); err != nil {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	decodedPassword, err := base64.StdEncoding.DecodeString(body.Password)

	if err != nil {
		log.Error().Msg("Failed to decode base64 password, err: " + err.Error())
		return c.SendStatus(fiber.StatusBadRequest)
	}

	if passwordValid := utils.IsPasswordLengthValid(string(decodedPassword)); !passwordValid {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	hashedPassword, err := bcrypt.GenerateFromPassword(decodedPassword, bcrypt.DefaultCost)

	if err != nil {
		log.Error().Msg("Failed to hash password, err: " + err.Error())
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	organizationId := uuid.New().String()
	userId := uuid.New().String()
	subdomain := utils.GenerateSubdomain()
	// roleId := uuid.New().String()

	if err := database.DB.Create(&models.Organization{
		Id:           organizationId,
		Subdomain:    subdomain,
		OwnerUserId:  userId,
		CompanyName:  "Mustermann GmbH",
		PrimaryColor: "1677ff", // blue
	}).Error; err != nil {
		logger.AddSystemLog(rslogger.LogTypeError, "Failed to create organization, err: "+err.Error())
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	/*
		if err := database.DB.Create(&models.Role{
			Id:             roleId,
			OrganizationId: organizationId,
			Master:         true,
			Name:           "Admin",
		}).Error; err != nil {
			logger.AddSystemLog(rslogger.LogTypeError, "Failed to create role, err: "+err.Error())
			return c.SendStatus(fiber.StatusInternalServerError)
		} */

	if err := database.DB.Create(&models.User{
		Id:             userId,
		OrganizationId: organizationId,
		FirstName:      "Max",
		LastName:       "Mustermann",
		Email:          body.Email,
		Password:       string(hashedPassword),
		RoleId:         utils.RoleAdminId,
	}).Error; err != nil {
		logger.AddSystemLog(rslogger.LogTypeError, "Failed to create user, err: "+err.Error())
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	session, err := rsutils.GenerateSession()

	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	if err := database.DB.Create(&models.UserSession{
		Id:             session,
		OrganizationId: organizationId,
		Session:        uuid.New().String(),
		UserId:         userId,
		UserAgent:      string(c.Context().UserAgent()),
		ExpiresAt:      utils.GetSessionExpiresAtTime(),
		LastUsedAt:     time.Now(),
	}).Error; err != nil {
		logger.AddSystemLog(rslogger.LogTypeError, "Failed to create user session, err: "+err.Error())
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	return c.JSON(structs.CreateOrganizationResponse{
		OrganizationSubdomain: subdomain,
		Session:               session,
	})
}

func IsSubdomainAvailable(c *fiber.Ctx) error {
	// swagger:operation GET /organization/subdomain/{subdomain} organization isSubdomainAvailable
	// ---
	// summary: Check if subdomain is available
	// produces:
	// - application/json
	// parameters:
	// - name: subdomain
	//   in: path
	//   required: true
	//   type: string
	// responses:
	//   '200':
	//     description: Subdomain is available
	//     schema:
	//       "$ref": "#/definitions/IsSubdomainAvailableResponse"
	//   '400':
	//     description: Invalid subdomain
	//   '500':
	//     description: Failed to check subdomain

	var params structs.SubdomainParam

	if err := rsutils.ParamsParserHelper(c, &params); err != nil {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	var organization models.Organization

	database.DB.Select("Id").Where("subdomain = ?", params.Subdomain).First(&organization)

	if organization.Id != "" {
		return c.JSON(structs.IsSubdomainAvailableResponse{
			Available: false,
		})
	}

	return c.JSON(structs.IsSubdomainAvailableResponse{
		Available: true,
	})
}
