package entity

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"go.mongodb.org/mongo-driver/bson"
)

const (
	ID           = "_id"
	Name         = "name"
	Relationship = "relationship"
	Type         = "type"
	Title        = "title"
	Text         = "text"
	Modified     = "modified"
	Connections  = "connections"
	Attachments  = "attachments"
	Location     = "location"
)

type One struct {
	ID          string                `bson:"_id,omitempty" json:"_id"`
	Name        string                `bson:"name,omitempty" json:"name"`
	Type        string                `bson:"type,omitempty" json:"type"`
	Title       string                `bson:"title,omitempty" json:"title"`
	Text        string                `bson:"text,omitempty" json:"text"`
	Modified    int64                 `bson:"modified,omitempty" json:"modified"`
	Connections map[string]Connection `bson:"connections" json:"connections"`
	Attachments map[string]Attachment `bson:"attachments" json:"attachments"`
}

type Connection struct {
	Relationship string `bson:"relationship,omitempty" json:"relationship"`
}

type Attachment struct {
	Location string `bson:"location,omitempty" json:"location"`
}

func (o One) Query() bson.M {
	return bson.M{ID: o.ID}
}

func (o One) Peers() []string {
	ids := make([]string, len(o.Connections))
	i := 0
	for k := range o.Connections {
		ids[i] = k
		i += 1
	}
	return ids
}

func (o One) MarshalBSON() ([]byte, error) {
	isMin := fmt.Sprint(o) == fmt.Sprint(o.Query())
	if !isMin {
		o.Modified = time.Now().UnixNano()
	}
	if o.Connections == nil {
		o.Connections = make(map[string]Connection)
	}
	if o.Attachments == nil {
		o.Attachments = make(map[string]Attachment)
	}
	b, err := json.Marshal(o)
	if err != nil {
		return nil, err
	}
	m := bson.M{}
	if err := json.Unmarshal(b, &m); err != nil {
		return nil, err
	}
	for k, v := range m {
		switch v.(type) {
		case string:
			m[k] = strings.TrimSpace(v.(string))
		}
	}
	return bson.Marshal(m)
}
