package authorization

import (
	"encoding/json"
	"fmt"
)

// Audience of the access token.
// This will generally be the callee service.
type Audience interface {
	Contains(host string) bool
	All() []string
	Add(string)
	String() string
}

// NewAudience returns a new audience object
func NewAudience(values ...string) Audience {
	out := &audience{values: make(map[string]interface{}, len(values))}
	for _, v := range values {
		out.Add(v)
	}
	return out
}

type audience struct {
	values map[string]interface{}
}

func (a *audience) All() []string {
	out := make([]string, 0, len(a.values))
	for k := range a.values {
		out = append(out, k)
	}
	return out
}

func (a *audience) Add(v string) {
	a.values[v] = nil
}

func (a audience) Contains(v string) bool {
	_, ok := a.values[v]
	return ok
}

func (a audience) String() string {
	return fmt.Sprintf("%v", a.All())
}

func (a audience) MarshalJSON() ([]byte, error) {
	if len(a.values) > 1 {
		return json.Marshal(a.All())
	}
	var only string
	for k := range a.values {
		only = k
	}
	return json.Marshal(only)
}

func (a *audience) UnmarshalJSON(in []byte) error {
	a.values = make(map[string]interface{})

	if len(in) > 0 && in[0] == '[' {
		values := make([]string, 0)
		if err := json.Unmarshal(in, &values); err != nil {
			return err
		}
		for _, v := range values {
			a.Add(v)
		}
		return nil
	}

	var value string
	if err := json.Unmarshal(in, &value); err != nil {
		return err
	}
	a.Add(value)
	return nil
}
