// Package memory provides in-memory implementations of port interfaces for testing.
package memory

import (
	"context"
	"sync"

	"github.com/orchard9/rdev/internal/domain"
	"github.com/orchard9/rdev/internal/port"
)

// ProjectRepository is an in-memory implementation of port.ProjectRepository.
type ProjectRepository struct {
	projects map[domain.ProjectID]*domain.Project
	mu       sync.RWMutex
}

// NewProjectRepository creates a new in-memory project repository.
func NewProjectRepository() *ProjectRepository {
	return &ProjectRepository{
		projects: make(map[domain.ProjectID]*domain.Project),
	}
}

// Ensure ProjectRepository implements port.ProjectRepository at compile time.
var _ port.ProjectRepository = (*ProjectRepository)(nil)

// List returns all available projects.
func (r *ProjectRepository) List(ctx context.Context) ([]domain.Project, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	projects := make([]domain.Project, 0, len(r.projects))
	for _, p := range r.projects {
		projects = append(projects, *p)
	}
	return projects, nil
}

// Get returns a project by ID.
func (r *ProjectRepository) Get(ctx context.Context, id domain.ProjectID) (*domain.Project, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	p, ok := r.projects[id]
	if !ok {
		return nil, domain.ErrProjectNotFound
	}
	return p, nil
}

// Exists checks if a project exists.
func (r *ProjectRepository) Exists(ctx context.Context, id domain.ProjectID) (bool, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	_, ok := r.projects[id]
	return ok, nil
}

// Register adds a new project to the repository.
func (r *ProjectRepository) Register(ctx context.Context, project *domain.Project) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	r.projects[project.ID] = project
	return nil
}

// Unregister removes a project from the repository.
func (r *ProjectRepository) Unregister(ctx context.Context, id domain.ProjectID) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	delete(r.projects, id)
	return nil
}

// RefreshStatus updates the status of all projects.
// For the in-memory implementation, this is a no-op.
func (r *ProjectRepository) RefreshStatus(ctx context.Context) error {
	return nil
}

// SetStatus is a test helper to set a project's status.
func (r *ProjectRepository) SetStatus(id domain.ProjectID, status domain.ProjectStatus) {
	r.mu.Lock()
	defer r.mu.Unlock()

	if p, ok := r.projects[id]; ok {
		p.Status = status
	}
}
