package events

import (
	"encoding/json"

	"github.com/google/uuid"
)

type Dest struct {
	Groups []DestGroup
	Items  []DestItem
}

func (d Dest) MarshalJSON() ([]byte, error) {
	dest := map[string]any{
		"groups": d.Groups,
		"items":  d.Items,
	}
	return json.Marshal(dest)
}

func (d *Dest) UnmarshalJSON(data []byte) error {
	dest := make(map[string]any)
	if err := json.Unmarshal(data, &dest); err != nil {
		return err
	}

	if v, ok := dest["groups"].([]any); ok {
		groups := make([]DestGroup, 0, len(v))
		for _, g := range v {
			groupData, err := json.Marshal(g)
			if err != nil {
				return err
			}
			var group DestGroup
			if err := json.Unmarshal(groupData, &group); err != nil {
				return err
			}
			groups = append(groups, group)
		}
		d.Groups = groups
	}

	if v, ok := dest["items"].([]any); ok {
		items := make([]DestItem, 0, len(v))
		for _, i := range v {
			itemData, err := json.Marshal(i)
			if err != nil {
				return err
			}
			var item DestItem
			if err := json.Unmarshal(itemData, &item); err != nil {
				return err
			}
			items = append(items, item)
		}
		d.Items = items
	}

	return nil
}

type DestGroup struct {
	ProjectUuid    uuid.UUID
	AgentGroupUuid uuid.UUID
	ClientKeyValue string
	ClientKeyUuid  uuid.UUID
}

func (g DestGroup) MarshalJSON() ([]byte, error) {
	group := map[string]any{
		"project_uuid":     g.ProjectUuid,
		"agent_group_uuid": g.AgentGroupUuid,
		"client_key_value": g.ClientKeyValue,
		"client_key_uuid":  g.ClientKeyUuid,
	}
	return json.Marshal(group)
}

func (g *DestGroup) UnmarshalJSON(data []byte) error {
	group := make(map[string]any)
	if err := json.Unmarshal(data, &group); err != nil {
		return err
	}

	if v, ok := group["project_uuid"].(string); ok {
		uuidVal, err := uuid.Parse(v)
		if err != nil {
			return err
		}
		g.ProjectUuid = uuidVal
	}

	if v, ok := group["agent_group_uuid"].(string); ok {
		uuidVal, err := uuid.Parse(v)
		if err != nil {
			return err
		}
		g.AgentGroupUuid = uuidVal
	}

	if v, ok := group["client_key_value"].(string); ok {
		g.ClientKeyValue = v
	}

	if v, ok := group["client_key_uuid"].(string); ok {
		uuidVal, err := uuid.Parse(v)
		if err != nil {
			return err
		}
		g.ClientKeyUuid = uuidVal
	}

	return nil
}

type DestItem struct {
	// AgentUuid or UserUuid
	ClientUuid uuid.UUID
	TokenUuid  uuid.UUID
	Token      string
}

func (i DestItem) MarshalJSON() ([]byte, error) {
	item := map[string]any{
		"client_uuid": i.ClientUuid,
		"token_uuid":  i.TokenUuid,
		"token":       i.Token,
	}
	return json.Marshal(item)
}

func (i *DestItem) UnmarshalJSON(data []byte) error {
	item := make(map[string]any)
	if err := json.Unmarshal(data, &item); err != nil {
		return err
	}

	if v, ok := item["client_uuid"].(string); ok {
		uuidVal, err := uuid.Parse(v)
		if err != nil {
			return err
		}
		i.ClientUuid = uuidVal
	}

	if v, ok := item["token_uuid"].(string); ok {
		uuidVal, err := uuid.Parse(v)
		if err != nil {
			return err
		}
		i.TokenUuid = uuidVal
	}

	if v, ok := item["token"].(string); ok {
		i.Token = v
	}

	return nil
}
