package usecase

import (
	"backend/pkg/permission/domain"
	"backend/pkg/permission/domain/entity"
	"backend/pkg/permission/domain/repository"
	"backend/pkg/permission/domain/usecase"
	"context"
	"fmt"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"
)

type UserRoleUseCaseParam struct {
	UserRoleRepo repository.UserRoleRepository
	RoleRepo     repository.RoleRepository
}

type userRoleUseCase struct {
	UserRoleUseCaseParam
}

// NewUserRoleUseCase 建立使用者角色 UseCase
func NewUserRoleUseCase(param UserRoleUseCaseParam) usecase.UserRoleUseCase {
	return &userRoleUseCase{
		UserRoleUseCaseParam: param,
	}
}

func (uc *userRoleUseCase) Assign(ctx context.Context, req usecase.AssignRoleRequest) (*usecase.UserRoleResponse, error) {
	// 檢查角色是否存在
	role, err := uc.RoleRepo.GetByUID(ctx, req.RoleUID)
	if err != nil {
		return nil, err
	}

	if !role.Status.IsActive() {
		return nil, fmt.Errorf("role is not active")
	}

	// 檢查使用者是否已有角色
	exists, err := uc.UserRoleRepo.Exists(ctx, req.UserUID)
	if err != nil {
		return nil, err
	}

	if exists {
		return nil, fmt.Errorf("user role already exists")
	}

	// 建立使用者角色
	now := time.Now().Unix()
	userRole := &entity.UserRole{
		ID:     bson.NewObjectID(),
		UID:    req.UserUID,
		RoleID: req.RoleUID,
		Brand:  req.Brand,
		Status: domain.RecordActive,
	}
	userRole.CreateTime = now
	userRole.UpdateTime = now

	if err := uc.UserRoleRepo.Create(ctx, userRole); err != nil {
		return nil, err
	}

	return uc.toResponse(userRole), nil
}

func (uc *userRoleUseCase) Update(ctx context.Context, userUID, roleUID string) (*usecase.UserRoleResponse, error) {
	// 檢查角色是否存在
	role, err := uc.RoleRepo.GetByUID(ctx, roleUID)
	if err != nil {
		return nil, err
	}

	if !role.Status.IsActive() {
		return nil, fmt.Errorf("role is not active")
	}

	// 更新使用者角色
	userRole, err := uc.UserRoleRepo.Update(ctx, userUID, roleUID)
	if err != nil {
		return nil, err
	}

	return uc.toResponse(userRole), nil
}

func (uc *userRoleUseCase) Remove(ctx context.Context, userUID string) error {
	return uc.UserRoleRepo.Delete(ctx, userUID)
}

func (uc *userRoleUseCase) Get(ctx context.Context, userUID string) (*usecase.UserRoleResponse, error) {
	userRole, err := uc.UserRoleRepo.Get(ctx, userUID)
	if err != nil {
		return nil, err
	}

	return uc.toResponse(userRole), nil
}

func (uc *userRoleUseCase) GetByRole(ctx context.Context, roleUID string) ([]*usecase.UserRoleResponse, error) {
	// 檢查角色是否存在
	if _, err := uc.RoleRepo.GetByUID(ctx, roleUID); err != nil {
		return nil, err
	}

	userRoles, err := uc.UserRoleRepo.GetByRoleID(ctx, roleUID)
	if err != nil {
		return nil, err
	}

	result := make([]*usecase.UserRoleResponse, 0, len(userRoles))
	for _, ur := range userRoles {
		result = append(result, uc.toResponse(ur))
	}

	return result, nil
}

func (uc *userRoleUseCase) List(ctx context.Context, filter usecase.UserRoleFilterRequest) ([]*usecase.UserRoleResponse, error) {
	repoFilter := repository.UserRoleFilter{
		Brand:  filter.Brand,
		RoleID: filter.RoleID,
		Status: filter.Status,
	}

	userRoles, err := uc.UserRoleRepo.List(ctx, repoFilter)
	if err != nil {
		return nil, err
	}

	result := make([]*usecase.UserRoleResponse, 0, len(userRoles))
	for _, ur := range userRoles {
		result = append(result, uc.toResponse(ur))
	}

	return result, nil
}

func (uc *userRoleUseCase) toResponse(userRole *entity.UserRole) *usecase.UserRoleResponse {
	return &usecase.UserRoleResponse{
		UserUID:    userRole.UID,
		RoleUID:    userRole.RoleID,
		Brand:      userRole.Brand,
		CreateTime: time.Unix(userRole.CreateTime, 0).UTC().Format(time.RFC3339),
		UpdateTime: time.Unix(userRole.UpdateTime, 0).UTC().Format(time.RFC3339),
	}
}
