package memory

import (
	"context"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/service/resource/access"
	"github.com/tidbcloud/AgentTeam/internal/service/resource/repos"
	memorystore "github.com/tidbcloud/AgentTeam/internal/store/resource/memory"
	reposstore "github.com/tidbcloud/AgentTeam/internal/store/resource/repos"
)

type agentCloudMemoryRepository struct {
	AgentID            string
	Memory             memorystore.Memory
	Branch             string
	Repo               repos.RepositoryIdentity
	ResourceRepository reposstore.ResourceRepository
	RepoName           string
	Workspace          string
}

func (s *MemoryService) ListAgentCloudMemoryBackups(ctx context.Context, workspaceID, subject, agentID, query string, page, perPage int) (AgentCloudMemoryBackupPage, error) {
	target, err := s.agentCloudMemoryRepository(ctx, workspaceID, subject, agentID)
	if err != nil {
		return AgentCloudMemoryBackupPage{}, err
	}
	if s.repositoryBackups == nil {
		return AgentCloudMemoryBackupPage{}, invalidArgument("memory repository backups are not configured")
	}
	return s.repositoryBackups.ListMemoryRepositoryBackups(ctx, MemoryRepositoryBackupListRequest{
		Repository: target.Repo,
		Query:      query,
		Page:       page,
		PerPage:    perPage,
	})
}

func (s *MemoryService) CreateAgentCloudMemoryBackup(ctx context.Context, workspaceID, subject, agentID string, input AgentCloudMemoryBackupCreateMutation) (AgentCloudMemoryBackup, error) {
	target, err := s.agentCloudMemoryRepository(ctx, workspaceID, subject, agentID)
	if err != nil {
		return AgentCloudMemoryBackup{}, err
	}
	if s.repositoryBackups == nil {
		return AgentCloudMemoryBackup{}, invalidArgument("memory repository backups are not configured")
	}
	authorName, authorEmail := repos.RepositoryCommitAuthorFromActor(input.Actor, "MeshX Memory", "meshx-memory@agentteam.local")
	return s.repositoryBackups.CreateMemoryRepositoryBackup(ctx, MemoryRepositoryBackupCreateRequest{
		Repository:  target.Repo,
		Branch:      target.Branch,
		Name:        input.Name,
		Now:         s.now(),
		AuthorName:  authorName,
		AuthorEmail: authorEmail,
	})
}

func (s *MemoryService) RestoreAgentCloudMemoryBackup(ctx context.Context, workspaceID, subject, agentID, tagName string) (AgentCloudMemoryBackup, error) {
	target, err := s.agentCloudMemoryRepository(ctx, workspaceID, subject, agentID)
	if err != nil {
		return AgentCloudMemoryBackup{}, err
	}
	if s.repositoryBackups == nil {
		return AgentCloudMemoryBackup{}, invalidArgument("memory repository backups are not configured")
	}
	result, err := s.repositoryBackups.RestoreMemoryRepositoryBackup(ctx, MemoryRepositoryBackupRestoreRequest{
		Repository: target.Repo,
		Branch:     target.Branch,
		TagName:    tagName,
		Now:        s.now(),
	})
	if err != nil {
		return AgentCloudMemoryBackup{}, err
	}
	if err := s.enqueueAgentMemoryRefresh(ctx, target.Workspace, target.AgentID); err != nil {
		return AgentCloudMemoryBackup{}, err
	}
	return result.Restored, nil
}

func (s *MemoryService) agentCloudMemoryRepository(ctx context.Context, workspaceID, subject, agentID string) (agentCloudMemoryRepository, error) {
	if s.store == nil {
		return agentCloudMemoryRepository{}, invalidArgument("memory service is not configured")
	}
	if err := validateSubject(subject); err != nil {
		return agentCloudMemoryRepository{}, err
	}
	workspaceID = strings.TrimSpace(workspaceID)
	agentID = strings.TrimSpace(agentID)
	if agentID == "" {
		return agentCloudMemoryRepository{}, invalidArgument("agent id is required")
	}
	current, err := s.GetAgentAccessibleMemory(ctx, workspaceID, subject, agentID)
	if err != nil {
		return agentCloudMemoryRepository{}, err
	}
	if current == nil || current.Repository == nil {
		return agentCloudMemoryRepository{}, notFound("cloud memory is not enabled")
	}
	memory, err := s.GetMemory(ctx, workspaceID, subject, current.ID)
	if err != nil {
		return agentCloudMemoryRepository{}, err
	}
	if !roleCanManage(s.memoryRole(ctx, workspaceID, memory, subject)) {
		return agentCloudMemoryRepository{}, forbidden("memory requires manager access")
	}
	repo := repos.IdentityFromStore(*current.Repository)
	repo.DefaultBranch = firstNonEmptyString(repo.DefaultBranch, current.Branch, "main")
	if strings.TrimSpace(repo.FullName) == "" || strings.TrimSpace(repo.Owner) == "" || strings.TrimSpace(repo.Name) == "" {
		return agentCloudMemoryRepository{}, invalidArgument("memory primary repository is not configured")
	}
	return agentCloudMemoryRepository{
		AgentID:            agentID,
		Memory:             memory,
		Branch:             firstNonEmptyString(current.Branch, repo.DefaultBranch, "main"),
		Repo:               repo,
		ResourceRepository: *current.Repository,
		RepoName:           repo.FullName,
		Workspace:          workspaceID,
	}, nil
}

func (s *MemoryService) enqueueAgentMemoryRefresh(ctx context.Context, workspaceID, agentID string) error {
	if s.store == nil {
		return nil
	}
	_, err := access.EnqueueAccessChange(ctx, s.store, memorystore.AgentAssetAccessChangeInput{
		WorkspaceID: workspaceID,
		AgentID:     agentID,
		AssetType:   access.AssetTypeMemory,
		OccurredAt:  s.now(),
	})
	return err
}
