package collaborative_area

import (
	"slices"
	"time"

	"cloud.o-forge.io/core/oc-lib/config"
	"cloud.o-forge.io/core/oc-lib/models/collaborative_area/rules/rule"
	"cloud.o-forge.io/core/oc-lib/models/peer"
	"cloud.o-forge.io/core/oc-lib/models/utils"
	w "cloud.o-forge.io/core/oc-lib/models/workflow"
	"cloud.o-forge.io/core/oc-lib/models/workspace"
	"cloud.o-forge.io/core/oc-lib/tools"
)

type CollaborativeAreaRule struct {
	ShareMode   string    `json:"share_mode,omitempty" bson:"share_mode,omitempty"`     // Share is the share of the rule
	CreatedAt   time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"`     // CreatedAt is the time the rule was created
	Creator     string    `json:"creator,omitempty" bson:"creator,omitempty"`           // Creator is the creator of the rule
	ExploitedBy string    `json:"exploited_by,omitempty" bson:"exploited_by,omitempty"` // ExploitedBy is the exploited by of the rule
}

// SharedWorkspace is a struct that represents a shared workspace
// WARNING : it got a shallow object version, this one is the full version
// full version is the one used by API
// other one is a shallow version used by the Lib for import cycle problem purposes
type CollaborativeArea struct {
	utils.AbstractObject                         // AbstractObject contains the basic fields of an object (id, name)
	IsSent                bool                   `json:"is_sent" bson:"-"`                                                       // IsSent is a flag that indicates if the workspace is sent
	Version               string                 `json:"version,omitempty" bson:"version,omitempty"`                             // Version is the version of the workspace
	Description           string                 `json:"description,omitempty" bson:"description,omitempty" validate:"required"` // Description is the description of the workspace
	CollaborativeAreaRule *CollaborativeAreaRule `json:"collaborative_area,omitempty" bson:"collaborative_area,omitempty"`       // CollaborativeArea is the collaborative area of the workspace
	Attributes            map[string]interface{} `json:"attributes,omitempty" bson:"attributes,omitempty"`                       // Attributes is the attributes of the workspace (TODO)
	Workspaces            []string               `json:"workspaces" bson:"workspaces"`                                           // Workspaces is the workspaces of the workspace
	Workflows             []string               `json:"workflows" bson:"workflows"`                                             // Workflows is the workflows of the workspace
	AllowedPeersGroup     map[string][]string    `json:"allowed_peers_group" bson:"allowed_peers_group"`                         // AllowedPeersGroup is the group of allowed peers
	Rules                 []string               `json:"rules" bson:"rules,omitempty"`                                           // Rules is the rules of the workspace

	SharedRules      []*rule.Rule           `json:"shared_rules,omitempty" bson:"-"`      // SharedRules is the shared rules of the workspace
	SharedWorkspaces []*workspace.Workspace `json:"shared_workspaces,omitempty" bson:"-"` // SharedWorkspaces is the shared workspaces of the workspace
	SharedWorkflows  []*w.Workflow          `json:"shared_workflows,omitempty" bson:"-"`  // SharedWorkflows is the shared workflows of the workspace
	SharedPeers      []*peer.Peer           `json:"shared_peers,omitempty" bson:"-"`      // SharedPeers is the shared peers of the workspace
}

func (ao *CollaborativeArea) Clear(peerID string) {
	if ao.AllowedPeersGroup == nil {
		ao.AllowedPeersGroup = map[string][]string{}
	}
	ao.CreatorID = peerID
	if config.GetConfig().Whitelist {
		ao.AllowedPeersGroup[peerID] = []string{"*"}
	} else {
		ao.AllowedPeersGroup[peerID] = []string{}
	}
	// then reset the shared fields
	if ao.Workspaces == nil {
		ao.Workspaces = []string{}
	}
	if ao.Workflows == nil {
		ao.Workflows = []string{}
	}
	if ao.Rules == nil {
		ao.Rules = []string{}
	}
	if ao.CollaborativeAreaRule == nil {
		ao.CollaborativeAreaRule = &CollaborativeAreaRule{
			ShareMode:   "private",
			ExploitedBy: "collaborators only",
		}
	}
	ao.CollaborativeAreaRule.CreatedAt = time.Now().UTC()
}

func (ao *CollaborativeArea) VerifyAuth(callName string, request *tools.APIRequest) bool {
	if (ao.AllowedPeersGroup != nil || config.GetConfig().Whitelist) && request != nil {
		if grps, ok := ao.AllowedPeersGroup[request.PeerID]; ok || config.GetConfig().Whitelist {
			if slices.Contains(grps, "*") || (!ok && config.GetConfig().Whitelist) {
				return true
			}
			for _, grp := range grps {
				if slices.Contains(request.Groups, grp) {
					return true
				}
			}
		}
	}
	return ao.AbstractObject.VerifyAuth(callName, request)
}

func (d *CollaborativeArea) GetAccessor(request *tools.APIRequest) utils.Accessor {
	return NewAccessor(request) // Create a new instance of the accessor
}

func (d *CollaborativeArea) StoreDraftDefault() {
	d.AllowedPeersGroup = map[string][]string{
		d.CreatorID: {"*"},
	}
	d.IsDraft = false
}
