package bootstrap

import (
	"context"
	"strings"

	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	"haixun-backend/internal/model/member/domain/entity"
	domrepo "haixun-backend/internal/model/member/domain/repository"

	"github.com/google/uuid"
	"golang.org/x/crypto/bcrypt"
)

type AdminOptions struct {
	TenantID    string
	Email       string
	Password    string
	DisplayName string
}

func EnsureAdminMember(ctx context.Context, repo domrepo.Repository, opts AdminOptions) (*entity.Member, bool, error) {
	tenantID := strings.TrimSpace(opts.TenantID)
	email := normalizeEmail(opts.Email)
	if tenantID == "" || email == "" || opts.Password == "" {
		return nil, false, app.For(code.Member).InputMissingRequired("tenant_id, email, and password are required")
	}
	if len(opts.Password) < 8 {
		return nil, false, app.For(code.Member).InputInvalidFormat("password must be at least 8 characters")
	}

	existing, err := repo.FindByEmail(ctx, tenantID, email)
	if err == nil {
		if err := repo.SetRoles(ctx, tenantID, existing.UID, []string{"admin"}); err != nil {
			return nil, false, err
		}
		existing.Roles = []string{"admin"}
		return existing, false, nil
	}
	if e := app.FromError(err); e == nil || e.Category() != code.ResNotFound {
		return nil, false, err
	}

	hash, err := bcrypt.GenerateFromPassword([]byte(opts.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, false, app.For(code.Member).SysInternal("hash password failed").WithCause(err)
	}
	displayName := strings.TrimSpace(opts.DisplayName)
	if displayName == "" {
		displayName = "Admin"
	}
	member, err := repo.Create(ctx, &entity.Member{
		TenantID:     tenantID,
		UID:          uuid.NewString(),
		Email:        email,
		DisplayName:  displayName,
		Language:     "zh-TW",
		Status:       entity.StatusOpen,
		Origin:       entity.OriginNative,
		PasswordHash: string(hash),
		Roles:        []string{"admin"},
	})
	if err != nil {
		return nil, false, err
	}
	return member, true, nil
}

func normalizeEmail(email string) string {
	return strings.ToLower(strings.TrimSpace(email))
}
