package service

import (
	"context"
	"github.com/google/uuid"
	"github.com/ocdp/cluster-service/internal/domain/entity"
	"github.com/ocdp/cluster-service/internal/domain/repository"
	"github.com/ocdp/cluster-service/internal/pkg/authz"
)

// RegistryService Registry 管理领域服务
type RegistryService struct {
	registryRepo repository.RegistryRepository
	ociClient    repository.OCIClient
}

// NewRegistryService 创建 Registry 服务
func NewRegistryService(
	registryRepo repository.RegistryRepository,
	ociClient repository.OCIClient,
) *RegistryService {
	return &RegistryService{
		registryRepo: registryRepo,
		ociClient:    ociClient,
	}
}

// CreateRegistry 创建新 Registry
func (s *RegistryService) CreateRegistry(ctx context.Context, registry *entity.Registry) error {
	principal, err := authz.RequirePrincipal(ctx)
	if err != nil {
		return entity.ErrUnauthorized
	}
	// 生成 ID
	registry.ID = uuid.New().String()
	registry.OwnerID = principal.UserID
	registry.WorkspaceID = principal.WorkspaceID
	if principal.IsAdmin() && registry.WorkspaceID == "" {
		registry.WorkspaceID = entity.DefaultWorkspaceID
	}
	if !principal.IsAdmin() && registry.Visibility == authz.VisibilityGlobalShared {
		return entity.ErrForbidden
	}
	registry.Visibility = authz.NormalizeVisibility(principal.Role, registry.Visibility)

	// 验证
	if err := registry.Validate(); err != nil {
		return err
	}

	// 检查是否已存在
	registries, _ := s.registryRepo.List(ctx)
	for _, existingRegistry := range registries {
		if existingRegistry.Name == registry.Name && existingRegistry.WorkspaceID == registry.WorkspaceID && existingRegistry.OwnerID == registry.OwnerID {
			return entity.ErrRegistryExists
		}
	}

	return s.registryRepo.Create(ctx, registry)
}

// GetRegistry 获取 Registry
func (s *RegistryService) GetRegistry(ctx context.Context, id string) (*entity.Registry, error) {
	principal, err := authz.RequirePrincipal(ctx)
	if err != nil {
		return nil, entity.ErrUnauthorized
	}
	registry, err := s.registryRepo.GetByID(ctx, id)
	if err != nil {
		return nil, err
	}
	if !authz.CanReadResource(principal, registry.WorkspaceID, registry.OwnerID, registry.Visibility) {
		return nil, entity.ErrRegistryNotFound
	}
	return registry, nil
}

// UpdateRegistry 更新 Registry
func (s *RegistryService) UpdateRegistry(ctx context.Context, registry *entity.Registry) error {
	principal, err := authz.RequirePrincipal(ctx)
	if err != nil {
		return entity.ErrUnauthorized
	}
	// 检查是否存在
	existing, err := s.registryRepo.GetByID(ctx, registry.ID)
	if err != nil {
		return entity.ErrRegistryNotFound
	}
	if !authz.CanWriteResource(principal, existing.WorkspaceID, existing.OwnerID, existing.Visibility) {
		return entity.ErrForbidden
	}
	registry.WorkspaceID = existing.WorkspaceID
	registry.OwnerID = existing.OwnerID
	if principal.IsAdmin() {
		registry.Visibility = authz.NormalizeVisibility(principal.Role, registry.Visibility)
	} else {
		registry.Visibility = existing.Visibility
	}

	// 验证
	if err := registry.Validate(); err != nil {
		return err
	}

	return s.registryRepo.Update(ctx, registry)
}

// DeleteRegistry 删除 Registry
func (s *RegistryService) DeleteRegistry(ctx context.Context, id string) error {
	principal, err := authz.RequirePrincipal(ctx)
	if err != nil {
		return entity.ErrUnauthorized
	}
	// 检查是否存在
	registry, err := s.registryRepo.GetByID(ctx, id)
	if err != nil {
		return entity.ErrRegistryNotFound
	}
	if !authz.CanWriteResource(principal, registry.WorkspaceID, registry.OwnerID, registry.Visibility) {
		return entity.ErrForbidden
	}

	return s.registryRepo.Delete(ctx, id)
}

// ListRegistries 列出所有 Registries
func (s *RegistryService) ListRegistries(ctx context.Context) ([]*entity.Registry, error) {
	principal, err := authz.RequirePrincipal(ctx)
	if err != nil {
		return nil, entity.ErrUnauthorized
	}
	registries, err := s.registryRepo.List(ctx)
	if err != nil {
		return nil, err
	}
	visible := make([]*entity.Registry, 0, len(registries))
	for _, registry := range registries {
		if authz.CanReadResource(principal, registry.WorkspaceID, registry.OwnerID, registry.Visibility) {
			visible = append(visible, registry)
		}
	}
	return visible, nil
}

// CheckHealth 检查 Registry 健康状态
func (s *RegistryService) CheckHealth(ctx context.Context, id string) error {
	registry, err := s.GetRegistry(ctx, id)
	if err != nil {
		return entity.ErrRegistryNotFound
	}

	return s.ociClient.CheckHealth(ctx, registry)
}
