package iamgenerator

import (
	"encoding/json"
	"strings"
)

type listOrString struct {
	raw []byte
}

func (los *listOrString) UnmarshalJSON(data []byte) error {
	los.raw = data
	_, err := los.AsSlice()
	return err
}

func (los listOrString) MarshalJSON() ([]byte, error) {
	asSlice, err := los.AsSlice()
	if err != nil {
		return nil, err
	}
	return json.Marshal(asSlice)
}

func (los listOrString) AsSlice() ([]string, error) {
	var values []string
	if err := json.Unmarshal(los.raw, &values); err == nil {
		return values, nil
	}

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

	return []string{value}, nil
}

func (los listOrString) Contains(value string) (bool, error) {
	items, err := los.AsSlice()
	if err != nil {
		return false, err
	}

	value = strings.ToLower(value)
	for _, item := range items {
		if strings.ToLower(item) == value {
			return true, nil
		}
	}

	return false, nil
}

type policyDocument struct {
	Statement []struct {
		Principal struct {
			AWS listOrString
		}
		Action listOrString
	}
}

func (pd policyDocument) AWSPrincipalsAllowedTo(action string) ([]string, error) {
	principals := make([]string, 0)
	for _, statement := range pd.Statement {
		allowed, err := statement.Action.Contains(action)
		if err != nil {
			return nil, err
		}

		if allowed {
			items, err := statement.Principal.AWS.AsSlice()
			if err != nil {
				return nil, err
			}

			principals = append(principals, items...)
		}
	}

	return principals, nil
}
