package usecase

import (
	"context"
	"errors"
	"strings"
	"time"

	member "gateway/internal/model/member/domain"
	"gateway/internal/model/member/domain/entity"
	"gateway/internal/model/member/domain/enum"
	domrepo "gateway/internal/model/member/domain/repository"
	domusecase "gateway/internal/model/member/domain/usecase"
)

type tenantUseCase struct {
	tenants domrepo.TenantRepository
}

// TenantUseCaseParam wires TenantUseCase.
type TenantUseCaseParam struct {
	Tenants domrepo.TenantRepository
}

// MustTenantUseCase constructs TenantUseCase.
func MustTenantUseCase(param TenantUseCaseParam) domusecase.TenantUseCase {
	if param.Tenants == nil {
		panic("member: tenant repository is required")
	}
	return &tenantUseCase{tenants: param.Tenants}
}

func (uc *tenantUseCase) Create(ctx context.Context, req *domusecase.CreateTenantRequest) (*domusecase.TenantDTO, error) {
	if req == nil || req.TenantID == "" || req.Slug == "" || req.Name == "" {
		return nil, errb.InputMissingRequired("tenant_id, slug and name are required")
	}
	prefix := normalizeUIDPrefix(req.UIDPrefix)
	if prefix == "" {
		prefix = normalizeUIDPrefix(req.Slug)
	}
	if len(prefix) < member.UIDPrefixMinLength || len(prefix) > member.UIDPrefixMaxLength {
		return nil, errb.InputInvalidFormat("uid_prefix must be 2-4 uppercase letters")
	}
	if _, err := uc.tenants.GetByUIDPrefix(ctx, prefix); err == nil {
		return nil, errb.ResAlreadyExist("uid_prefix already exists")
	} else if !errors.Is(err, member.ErrTenantNotFound) {
		return nil, wrapRepoErr(err, "read tenant failed")
	}
	now := time.Now().UTC().UnixMilli()
	rec := &entity.Tenant{
		TenantID:  req.TenantID,
		Slug:      strings.ToLower(req.Slug),
		Name:      req.Name,
		UIDPrefix: prefix,
		Status:    enum.TenantStatusActive,
		CreateAt:  now,
		UpdateAt:  now,
	}
	if err := uc.tenants.Insert(ctx, rec); err != nil {
		if errors.Is(err, member.ErrDuplicateTenant) {
			return nil, errb.ResAlreadyExist("tenant already exists").WithCause(err)
		}
		return nil, wrapRepoErr(err, "create tenant failed")
	}
	return tenantToDTO(rec), nil
}

func (uc *tenantUseCase) ResolveBySlug(ctx context.Context, slug string) (*domusecase.TenantDTO, error) {
	if slug == "" {
		return nil, errb.InputMissingRequired("slug is required")
	}
	rec, err := uc.tenants.GetBySlug(ctx, strings.ToLower(slug))
	if err != nil {
		if errors.Is(err, member.ErrTenantNotFound) {
			return nil, errb.ResNotFound("tenant", slug).WithCause(err)
		}
		return nil, wrapRepoErr(err, "read tenant failed")
	}
	return tenantToDTO(rec), nil
}
