package pubsub

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"oc-discovery/conf"
	"oc-discovery/daemons/node/common"
	"oc-discovery/daemons/node/stream"
	"oc-discovery/models"
	"time"

	"cloud.o-forge.io/core/oc-lib/dbs"
	"cloud.o-forge.io/core/oc-lib/models/peer"
	"cloud.o-forge.io/core/oc-lib/tools"
)

func (ps *PubSubService) SearchPublishEvent(
	ctx context.Context, dt *tools.DataType, typ string, user string, groups []string, search string) error {
	b, err := json.Marshal(map[string]string{"search": search})
	if err != nil {
		return err
	}
	switch typ {
	case "known": // define Search Strategy
		return ps.StreamService.PublishesCommon(dt, user, groups, nil, b, stream.ProtocolSearchResource) //if partners focus only them*/
	case "partner": // define Search Strategy
		return ps.StreamService.PublishesCommon(dt, user, groups, &dbs.Filters{ // filter by like name, short_description, description, owner, url if no filters are provided
			Or: map[string][]dbs.Filter{
				"relation": {{Operator: dbs.EQUAL.String(), Value: peer.PARTNER}},
				"is_nano":  {{Operator: dbs.EQUAL.String(), Value: true}},
			},
		}, b, stream.ProtocolSearchResource)
	case "all": // Gossip PubSub
		b, err := json.Marshal(map[string]string{"search": search})
		if err != nil {
			return err
		}
		idleTimeout := func() time.Duration {
			if t := conf.GetConfig().SearchTimeout; t > 0 {
				return time.Duration(t) * time.Second
			}
			return 5 * time.Second
		}()
		searchCtx, cancel := context.WithCancel(ctx)
		// Register cancels any previous search for this user and starts the idle timer.
		// The returned composite key is used as User in the GossipSub event so that
		// remote peers echo it back unchanged, allowing IsActive to validate results.
		searchKey := ps.StreamService.ResourceSearches.Register(user, cancel, idleTimeout)
		fmt.Println("PUBLISH ON PUBSUB", common.TopicPubSubSearch, searchKey)
		return ps.publishEvent(searchCtx, dt, tools.PB_SEARCH, common.TopicPubSubSearch, user, b)
	default:
		return errors.New("no type of research found")
	}
}

func (ps *PubSubService) publishEvent(
	ctx context.Context, dt *tools.DataType, action tools.PubSubAction, topicName string, user string, payload []byte,
) error {
	priv, err := tools.LoadKeyFromFilePrivate()
	if err != nil {
		return err
	}
	msg, _ := json.Marshal(models.NewEvent(action.String(), ps.Host.ID().String(), dt, user, payload, priv))
	topic := ps.Node.GetPubSub(topicName)
	if topic == nil {
		topic, err = ps.PS.Join(topicName)
		if err != nil {
			return err
		}
	}
	return topic.Publish(ctx, msg)
}

// TODO REVIEW PUBLISHING + ADD SEARCH ON PUBLIC : YES
// TODO : Search should verify DataType
