// Package usecase implements the permission module's domain interfaces.
// Use NewModuleFromParam (module.go) to wire all seven usecases against a
// shared Mongo + Redis backend.
package usecase

import (
	"context"

	"gateway/internal/model/permission/domain/entity"
	"gateway/internal/model/permission/domain/enum"
	domrepo "gateway/internal/model/permission/domain/repository"
	dom "gateway/internal/model/permission/domain/usecase"
)

// PermissionUseCaseParam injects the catalog repository.
type PermissionUseCaseParam struct {
	Permissions domrepo.PermissionRepository
}

type permissionUseCase struct {
	repo domrepo.PermissionRepository
}

// NewPermissionUseCase returns the catalog-facing usecase.
func NewPermissionUseCase(param PermissionUseCaseParam) dom.PermissionUseCase {
	return &permissionUseCase{repo: param.Permissions}
}

func (uc *permissionUseCase) GetCatalogTree(
	ctx context.Context,
	query *dom.CatalogQuery,
) ([]*dom.PermissionTreeNode, error) {
	perms, err := uc.repo.GetAll(ctx, nil)
	if err != nil {
		return nil, wrapRepoErr(err)
	}
	tree := buildPermissionTree(perms)
	if query == nil {
		return tree, nil
	}
	if query.OnlyOpen {
		tree = filterOpenNodes(tree)
	}
	if query.Type != nil {
		tree = filterByType(tree, *query.Type)
	}
	return tree, nil
}

func (uc *permissionUseCase) List(ctx context.Context, query *dom.CatalogQuery) ([]*entity.Permission, error) {
	var status *enum.Status
	if query != nil && query.OnlyOpen {
		open := enum.StatusOpen
		status = &open
	}
	perms, err := uc.repo.GetAll(ctx, status)
	if err != nil {
		return nil, wrapRepoErr(err)
	}
	if query != nil && query.Type != nil {
		filtered := perms[:0]
		for _, p := range perms {
			if p.Type == *query.Type {
				filtered = append(filtered, p)
			}
		}
		perms = filtered
	}
	return perms, nil
}

func (uc *permissionUseCase) GetByID(ctx context.Context, id string) (*entity.Permission, error) {
	perm, err := uc.repo.GetByID(ctx, id)
	if err != nil {
		return nil, wrapRepoErr(err)
	}
	return perm, nil
}

func (uc *permissionUseCase) GetByName(ctx context.Context, name string) (*entity.Permission, error) {
	perm, err := uc.repo.GetByName(ctx, name)
	if err != nil {
		return nil, wrapRepoErr(err)
	}
	return perm, nil
}

func (uc *permissionUseCase) UpsertCatalog(ctx context.Context, perms []*entity.Permission) error {
	for _, perm := range perms {
		if perm.Status == "" {
			perm.Status = enum.StatusOpen
		}
		if err := uc.repo.UpsertByName(ctx, perm); err != nil {
			return wrapRepoErr(err, "upsert catalog")
		}
	}
	return nil
}

func (uc *permissionUseCase) UpdateStatus(ctx context.Context, id string, status enum.Status) error {
	if !status.IsValid() {
		return errb.InputInvalidFormat("invalid status").WithCause(nil)
	}
	if err := uc.repo.UpdateStatus(ctx, id, status); err != nil {
		return wrapRepoErr(err, "update status")
	}
	return nil
}

var _ dom.PermissionUseCase = (*permissionUseCase)(nil)
