package dashboard

import (
	"context"
	"math/rand"
	"sync"

	"github.com/coder/coder/v2/codersdk"
)

type cache struct {
	sync.RWMutex
	workspaces []codersdk.Workspace
	templates  []codersdk.Template
	users      []codersdk.User
}

func (c *cache) fill(ctx context.Context, client *codersdk.Client) error {
	c.Lock()
	defer c.Unlock()
	me, err := client.User(ctx, codersdk.Me)
	if err != nil {
		return err
	}
	ws, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{})
	if err != nil {
		return err
	}
	c.workspaces = ws.Workspaces
	tpl, err := client.TemplatesByOrganization(ctx, me.OrganizationIDs[0])
	if err != nil {
		return err
	}
	c.templates = tpl
	users, err := client.Users(ctx, codersdk.UsersRequest{})
	if err != nil {
		return err
	}
	c.users = users.Users
	return nil
}

func (c *cache) setWorkspaces(ws []codersdk.Workspace) {
	c.Lock()
	c.workspaces = ws
	c.Unlock()
}

func (c *cache) setTemplates(t []codersdk.Template) {
	c.Lock()
	c.templates = t
	c.Unlock()
}

func (c *cache) randWorkspace() codersdk.Workspace {
	c.RLock()
	defer c.RUnlock()
	if len(c.workspaces) == 0 {
		return codersdk.Workspace{}
	}
	return pick(c.workspaces)
}

func (c *cache) randTemplate() codersdk.Template {
	c.RLock()
	defer c.RUnlock()
	if len(c.templates) == 0 {
		return codersdk.Template{}
	}
	return pick(c.templates)
}

func (c *cache) setUsers(u []codersdk.User) {
	c.Lock()
	c.users = u
	c.Unlock()
}

func (c *cache) randUser() codersdk.User {
	c.RLock()
	defer c.RUnlock()
	if len(c.users) == 0 {
		return codersdk.User{}
	}
	return pick(c.users)
}

// pick chooses a random element from a slice.
// If the slice is empty, it returns the zero value of the type.
func pick[T any](s []T) T {
	if len(s) == 0 {
		var zero T
		return zero
	}
	// nolint:gosec
	return s[rand.Intn(len(s))]
}
