package handler import ( "context" "fmt" "sync" "time" "code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/models" ) // mockAgentRepo implements repository.AgentRepo in-memory for testing. type mockAgentRepo struct { mu sync.RWMutex m map[string]models.AgentCardData } func newMockAgentRepo() *mockAgentRepo { return &mockAgentRepo{m: make(map[string]models.AgentCardData)} } func (r *mockAgentRepo) Create(ctx context.Context, a models.AgentCardData) error { r.mu.Lock() defer r.mu.Unlock() if _, ok := r.m[a.ID]; ok { return fmt.Errorf("duplicate key: %s", a.ID) } r.m[a.ID] = a return nil } func (r *mockAgentRepo) Get(ctx context.Context, id string) (models.AgentCardData, error) { r.mu.RLock() defer r.mu.RUnlock() a, ok := r.m[id] if !ok { return a, fmt.Errorf("not found: %s", id) } return a, nil } func (r *mockAgentRepo) List(ctx context.Context, statusFilter models.AgentStatus) ([]models.AgentCardData, error) { r.mu.RLock() defer r.mu.RUnlock() result := make([]models.AgentCardData, 0, len(r.m)) for _, a := range r.m { if statusFilter != "" && a.Status != statusFilter { continue } result = append(result, a) } return result, nil } func (r *mockAgentRepo) Update(ctx context.Context, id string, req models.UpdateAgentRequest) (models.AgentCardData, error) { r.mu.Lock() defer r.mu.Unlock() a, ok := r.m[id] if !ok { return a, fmt.Errorf("not found: %s", id) } if req.Status != nil { a.Status = *req.Status } if req.CurrentTask != nil { a.CurrentTask = req.CurrentTask } if req.TaskProgress != nil { a.TaskProgress = req.TaskProgress } if req.TaskElapsed != nil { a.TaskElapsed = req.TaskElapsed } if req.Channel != nil { a.Channel = *req.Channel } if req.ErrorMessage != nil { a.ErrorMessage = req.ErrorMessage } a.LastActivity = time.Now().UTC().Format(time.RFC3339) r.m[id] = a return a, nil } func (r *mockAgentRepo) Delete(ctx context.Context, id string) error { r.mu.Lock() defer r.mu.Unlock() if _, ok := r.m[id]; !ok { return fmt.Errorf("not found: %s", id) } delete(r.m, id) return nil } func (r *mockAgentRepo) Count(ctx context.Context) (int, error) { r.mu.RLock() defer r.mu.RUnlock() return len(r.m), nil } // ─── Mock Session Repo ────────────────────────────────────────────────────────── type mockSessionRepo struct { mu sync.RWMutex m map[string]models.Session } func newMockSessionRepo() *mockSessionRepo { return &mockSessionRepo{m: make(map[string]models.Session)} } func (r *mockSessionRepo) Create(ctx context.Context, s models.Session) (models.Session, error) { r.mu.Lock() defer r.mu.Unlock() if s.ID == "" { s.ID = fmt.Sprintf("sess-%d", len(r.m)+1) } if s.StartedAt.IsZero() { s.StartedAt = time.Now().UTC() } if s.LastActivityAt.IsZero() { s.LastActivityAt = s.StartedAt } r.m[s.ID] = s return s, nil } func (r *mockSessionRepo) ListActive(ctx context.Context) ([]models.Session, error) { r.mu.RLock() defer r.mu.RUnlock() result := make([]models.Session, 0) for _, s := range r.m { if s.Status == "running" || s.Status == "streaming" { result = append(result, s) } } return result, nil } func (r *mockSessionRepo) Count(ctx context.Context) (int, error) { r.mu.RLock() defer r.mu.RUnlock() return len(r.m), nil } // ─── Mock Task Repo ───────────────────────────────────────────────────────────── type mockTaskRepo struct { mu sync.RWMutex m map[string]models.Task } func newMockTaskRepo() *mockTaskRepo { return &mockTaskRepo{m: make(map[string]models.Task)} } func (r *mockTaskRepo) Create(ctx context.Context, t models.Task) (models.Task, error) { r.mu.Lock() defer r.mu.Unlock() if t.ID == "" { t.ID = fmt.Sprintf("task-%d", len(r.m)+1) } now := time.Now().UTC() if t.CreatedAt.IsZero() { t.CreatedAt = now } if t.UpdatedAt.IsZero() { t.UpdatedAt = now } r.m[t.ID] = t return t, nil } func (r *mockTaskRepo) ListRecent(ctx context.Context) ([]models.Task, error) { r.mu.RLock() defer r.mu.RUnlock() result := make([]models.Task, 0, len(r.m)) for _, t := range r.m { result = append(result, t) } return result, nil } func (r *mockTaskRepo) Count(ctx context.Context) (int, error) { r.mu.RLock() defer r.mu.RUnlock() return len(r.m), nil } // ─── Mock Project Repo ───────────────────────────────────────────────────────── type mockProjectRepo struct { mu sync.RWMutex m map[string]models.Project } func newMockProjectRepo() *mockProjectRepo { return &mockProjectRepo{m: make(map[string]models.Project)} } func (r *mockProjectRepo) Create(ctx context.Context, p models.Project) (models.Project, error) { r.mu.Lock() defer r.mu.Unlock() if p.ID == "" { p.ID = fmt.Sprintf("proj-%d", len(r.m)+1) } now := time.Now().UTC() if p.CreatedAt.IsZero() { p.CreatedAt = now } if p.UpdatedAt.IsZero() { p.UpdatedAt = now } if p.AgentIDs == nil { p.AgentIDs = []string{} } r.m[p.ID] = p return p, nil } func (r *mockProjectRepo) List(ctx context.Context) ([]models.Project, error) { r.mu.RLock() defer r.mu.RUnlock() result := make([]models.Project, 0, len(r.m)) for _, p := range r.m { result = append(result, p) } return result, nil } func (r *mockProjectRepo) Count(ctx context.Context) (int, error) { r.mu.RLock() defer r.mu.RUnlock() return len(r.m), nil }