package usecase

import (
	"context"
	"errors"
	"strings"

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

type profileUseCase struct {
	members domrepo.MemberRepository
}

// ProfileUseCaseParam wires ProfileUseCase.
type ProfileUseCaseParam struct {
	Members domrepo.MemberRepository
}

// MustProfileUseCase constructs ProfileUseCase.
func MustProfileUseCase(param ProfileUseCaseParam) domusecase.ProfileUseCase {
	if param.Members == nil {
		panic("member: member repository is required")
	}
	return &profileUseCase{members: param.Members}
}

func (uc *profileUseCase) GetByUID(ctx context.Context, req *domusecase.GetMemberRequest) (*domusecase.MemberDTO, error) {
	if req == nil || req.TenantID == "" || req.UID == "" {
		return nil, errb.InputMissingRequired("tenant_id and uid are required")
	}
	rec, err := uc.members.GetByUID(ctx, req.TenantID, req.UID)
	if err != nil {
		if errors.Is(err, member.ErrNotFound) {
			return nil, errb.ResNotFound("member", req.UID).WithCause(err)
		}
		return nil, wrapRepoErr(err, "read member failed")
	}
	return memberToDTO(rec), nil
}

func (uc *profileUseCase) GetByZitadelUserID(ctx context.Context, tenantID, zitadelUserID string) (*domusecase.MemberDTO, error) {
	if tenantID == "" || zitadelUserID == "" {
		return nil, errb.InputMissingRequired("tenant_id and zitadel_user_id are required")
	}
	rec, err := uc.members.GetByZitadelUserID(ctx, tenantID, zitadelUserID)
	if err != nil {
		if errors.Is(err, member.ErrNotFound) {
			return nil, errb.ResNotFound("member", zitadelUserID).WithCause(err)
		}
		return nil, wrapRepoErr(err, "read member failed")
	}
	return memberToDTO(rec), nil
}

func (uc *profileUseCase) GetByZitadelEmail(ctx context.Context, tenantID, email string) (*domusecase.MemberDTO, error) {
	if tenantID == "" || strings.TrimSpace(email) == "" {
		return nil, errb.InputMissingRequired("tenant_id and email are required")
	}
	rec, err := uc.members.GetByZitadelEmail(ctx, tenantID, strings.ToLower(strings.TrimSpace(email)))
	if err != nil {
		if errors.Is(err, member.ErrNotFound) {
			return nil, errb.ResNotFound("member", email).WithCause(err)
		}
		return nil, wrapRepoErr(err, "read member failed")
	}
	return memberToDTO(rec), nil
}

func (uc *profileUseCase) Update(ctx context.Context, req *domusecase.UpdateMemberRequest) (*domusecase.MemberDTO, error) {
	if req == nil || req.TenantID == "" || req.UID == "" {
		return nil, errb.InputMissingRequired("tenant_id and uid are required")
	}
	rec, err := uc.members.UpdateProfile(ctx, req.TenantID, req.UID, &domrepo.MemberUpdate{
		DisplayName: req.DisplayName,
		Avatar:      req.Avatar,
		Language:    req.Language,
		Currency:    req.Currency,
		Phone:       req.Phone,
	})
	if err != nil {
		if errors.Is(err, member.ErrNotFound) {
			return nil, errb.ResNotFound("member", req.UID).WithCause(err)
		}
		return nil, wrapRepoErr(err, "update member failed")
	}
	return memberToDTO(rec), nil
}

func (uc *profileUseCase) List(ctx context.Context, req *domusecase.ListMembersRequest) (*domusecase.ListMembersResponse, error) {
	if req == nil || req.TenantID == "" {
		return nil, errb.InputMissingRequired("tenant_id is required")
	}
	items, total, err := uc.members.List(ctx, domrepo.ListMembersFilter{
		TenantID: req.TenantID,
		Status:   req.Status,
		Offset:   req.Offset,
		Limit:    req.Limit,
	})
	if err != nil {
		return nil, wrapRepoErr(err, "list members failed")
	}
	out := make([]*domusecase.MemberDTO, 0, len(items))
	for _, item := range items {
		out = append(out, memberToDTO(item))
	}
	return &domusecase.ListMembersResponse{
		Items:  out,
		Total:  total,
		Offset: req.Offset,
		Limit:  req.Limit,
	}, nil
}

func (uc *profileUseCase) SetBusinessEmailVerified(ctx context.Context, tenantID, uid, email string) error {
	if tenantID == "" || uid == "" || email == "" {
		return errb.InputMissingRequired("tenant_id, uid and email are required")
	}
	if err := uc.members.SetBusinessEmailVerified(ctx, tenantID, uid, email); err != nil {
		if errors.Is(err, member.ErrNotFound) {
			return errb.ResNotFound("member", uid).WithCause(err)
		}
		return wrapRepoErr(err, "set business email verified failed")
	}
	return nil
}

func (uc *profileUseCase) SetBusinessPhoneVerified(ctx context.Context, tenantID, uid, phone string) error {
	if tenantID == "" || uid == "" || phone == "" {
		return errb.InputMissingRequired("tenant_id, uid and phone are required")
	}
	if err := uc.members.SetBusinessPhoneVerified(ctx, tenantID, uid, phone); err != nil {
		if errors.Is(err, member.ErrNotFound) {
			return errb.ResNotFound("member", uid).WithCause(err)
		}
		return wrapRepoErr(err, "set business phone verified failed")
	}
	return nil
}
