package admin

import (
	"net/mail"
	"slices"
	"strconv"
	"strings"

	"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
	"github.com/ultisuite/ulti-backend/internal/permission"
)

const maxQuotaRequestBody = 4 << 10

type setQuotaRequest struct {
	MailMaxStorageBytes   *int64 `json:"mail_max_storage_bytes"`
	DriveMaxStorageBytes  *int64 `json:"drive_max_storage_bytes"`
	PhotosMaxStorageBytes *int64 `json:"photos_max_storage_bytes"`
}

func validateSetQuota(req *setQuotaRequest) *apivalidate.ValidationError {
	if req.MailMaxStorageBytes == nil && req.DriveMaxStorageBytes == nil && req.PhotosMaxStorageBytes == nil {
		return apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "quota", Message: "at least one quota field is required"})
	}
	details := make([]apivalidate.FieldDetail, 0, 3)
	if req.MailMaxStorageBytes != nil && *req.MailMaxStorageBytes < 0 {
		details = append(details, apivalidate.FieldDetail{Field: "mail_max_storage_bytes", Message: "must be non-negative"})
	}
	if req.DriveMaxStorageBytes != nil && *req.DriveMaxStorageBytes < 0 {
		details = append(details, apivalidate.FieldDetail{Field: "drive_max_storage_bytes", Message: "must be non-negative"})
	}
	if req.PhotosMaxStorageBytes != nil && *req.PhotosMaxStorageBytes < 0 {
		details = append(details, apivalidate.FieldDetail{Field: "photos_max_storage_bytes", Message: "must be non-negative"})
	}
	if len(details) > 0 {
		return apivalidate.NewValidationError(details...)
	}
	return nil
}

type createUserRequest struct {
	ExternalID string `json:"external_id"`
	Email      string `json:"email"`
	Name       string `json:"name"`
}

func validateCreateUser(req *createUserRequest) *apivalidate.ValidationError {
	details := make([]apivalidate.FieldDetail, 0, 2)
	if strings.TrimSpace(req.ExternalID) == "" {
		details = append(details, apivalidate.FieldDetail{Field: "external_id", Message: "required"})
	}
	if _, err := mail.ParseAddress(strings.TrimSpace(req.Email)); err != nil {
		details = append(details, apivalidate.FieldDetail{Field: "email", Message: "must be valid"})
	}
	if len(details) > 0 {
		return apivalidate.NewValidationError(details...)
	}
	return nil
}

type inviteUserRequest struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

func validateInviteUser(req *inviteUserRequest) *apivalidate.ValidationError {
	if _, err := mail.ParseAddress(strings.TrimSpace(req.Email)); err != nil {
		return apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "email", Message: "must be valid"})
	}
	return nil
}

type updateUserRequest struct {
	Email *string `json:"email"`
	Name  *string `json:"name"`
}

func validateUpdateUser(req *updateUserRequest) *apivalidate.ValidationError {
	if req.Email == nil && req.Name == nil {
		return apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "user", Message: "at least one field is required"})
	}
	if req.Email != nil {
		if _, err := mail.ParseAddress(strings.TrimSpace(*req.Email)); err != nil {
			return apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "email", Message: "must be valid"})
		}
	}
	return nil
}

func validateExportFormat(raw string) (string, *apivalidate.ValidationError) {
	format := strings.TrimSpace(raw)
	if format == "" {
		return "ndjson", nil
	}
	if !slices.Contains([]string{"ndjson", "csv"}, format) {
		return "", apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "format", Message: "must be one of: ndjson,csv"})
	}
	return format, nil
}

func validateExportLimit(raw string) (int, *apivalidate.ValidationError) {
	val := strings.TrimSpace(raw)
	if val == "" {
		return 5000, nil
	}
	limit, err := strconv.Atoi(val)
	if err != nil || limit < 1 || limit > 10000 {
		return 0, apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "limit", Message: "must be between 1 and 10000"})
	}
	return limit, nil
}

func validateStatus(raw string) (string, *apivalidate.ValidationError) {
	status := strings.ToLower(strings.TrimSpace(raw))
	if status == "" {
		return "", nil
	}
	if !slices.Contains([]string{"active", "disabled", "invited"}, status) {
		return "", apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "status", Message: "must be one of: active,disabled,invited"})
	}
	return status, nil
}

func validateUserID(userID string) *apivalidate.ValidationError {
	if strings.TrimSpace(userID) == "" {
		return apivalidate.NewValidationError(apivalidate.FieldDetail{Field: "userID", Message: "required"})
	}
	return nil
}

type setUserRoleRequest struct {
	Role string `json:"role"`
}

func validateSetUserRole(req *setUserRoleRequest) *apivalidate.ValidationError {
	if _, ok := permission.ParseAccountRole(req.Role); !ok {
		return apivalidate.NewValidationError(apivalidate.FieldDetail{
			Field:   "role",
			Message: "must be one of: admin,user,guest,suspended",
		})
	}
	return nil
}

func validateAccountRoleFilter(raw string) (string, *apivalidate.ValidationError) {
	role := strings.ToLower(strings.TrimSpace(raw))
	if role == "" {
		return "", nil
	}
	if _, ok := permission.ParseAccountRole(role); !ok {
		return "", apivalidate.NewValidationError(apivalidate.FieldDetail{
			Field:   "role",
			Message: "must be one of: admin,user,guest,suspended",
		})
	}
	return role, nil
}
