package server

import (
	"context"
	"errors"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/service/repotokens"
	"github.com/tidbcloud/AgentTeam/internal/service/resource/repos"
)

// repositorySyncTokenIssuer adapts the MeshX credential authority to resource
// repository sync callers. AGS remains only the Git/repository execution plane.
type repositorySyncTokenIssuer struct {
	service *repotokens.Service
}

func repositorySyncTokenIssuerOption(service *repotokens.Service) repos.RepositorySyncTokenIssuer {
	return repositorySyncTokenIssuer{service: service}
}

func (i repositorySyncTokenIssuer) CreateRepositorySyncToken(ctx context.Context, req repos.RepositorySyncTokenRequest) (repos.RepositorySyncTokenLease, error) {
	providerHost := strings.TrimSpace(req.ProviderHost)
	if providerHost == "" {
		providerHost = repos.RepositorySyncTokenDefaultProviderHost
	}
	result, err := i.service.CreateSyncLease(ctx, repotokens.CreateSyncLeaseRequest{
		WorkspaceID:      req.WorkspaceID,
		ActorPrincipalID: req.ActorPrincipalID,
		DisplayName:      req.DisplayName,
		ProviderHost:     providerHost,
		RepositoryScope: repotokens.RepositoryScope{
			Mode:         repos.RepositorySyncTokenScopeRepositories,
			Repositories: append([]string(nil), req.Repositories...),
		},
		Capabilities: append([]string(nil), req.Capabilities...),
		ExpiresAt:    req.ExpiresAt,
	})
	if err != nil {
		return repos.RepositorySyncTokenLease{}, mapRepositorySyncTokenErr(err)
	}
	if result.Token.ExpiresAt == nil {
		return repos.RepositorySyncTokenLease{}, meshxServiceError(repos.ErrInvalidArgument, "repository sync lease is missing expiresAt")
	}
	return repos.RepositorySyncTokenLease{Token: result.Plaintext, ExpiresAt: *result.Token.ExpiresAt}, nil
}

func mapRepositorySyncTokenErr(err error) error {
	if err == nil {
		return nil
	}
	message := strings.TrimSpace(err.Error())
	switch {
	case errors.Is(err, repotokens.ErrPermissionDenied):
		return meshxServiceError(repos.ErrForbidden, message)
	case errors.Is(err, repotokens.ErrInvalidRequest):
		return meshxServiceError(repos.ErrInvalidArgument, message)
	case errors.Is(err, repotokens.ErrTokenStateConflict):
		return meshxServiceError(repos.ErrConflict, message)
	default:
		return err
	}
}

func meshxServiceError(kind error, message string) error {
	if strings.TrimSpace(message) == "" && kind != nil {
		message = kind.Error()
	}
	return fmt.Errorf("%w: %s", kind, message)
}
