package cft

import (
	"fmt"

	"github.com/aws-cloudformation/rain/internal/s11n"
	"gopkg.in/yaml.v3"
)

// Comment represents a path to a node and a comment string to attach to it
type Comment struct {
	Path  []interface{}
	Value string
}

// AddComments applies a set of comments to the template
func (t Template) AddComments(comments []*Comment) error {
	node := t.Node

	if node.Kind == yaml.DocumentNode {
		node = node.Content[0]
	}

	for _, comment := range comments {
		var n *yaml.Node
		var err error

		if len(comment.Path) == 0 {
			n, err = s11n.GetPath(node, comment.Path)
			if err != nil {
				return err
			}

			if len(n.Content) == 0 {
				return fmt.Errorf("unable to set head at node root")
			}

			n.Content[0].HeadComment = comment.Value

			continue
		}

		path, last := comment.Path[0:len(comment.Path)-1], comment.Path[len(comment.Path)-1]

		n, err = s11n.GetPath(node, path)
		if err != nil {
			return err
		}

		switch v := last.(type) {
		case string:
			key, value, _ := s11n.GetMapValue(n, v)
			if value == nil {
				return fmt.Errorf("can't find map key: '%s'", v)
			}

			switch value.Kind {
			case yaml.MappingNode, yaml.SequenceNode:
				if len(value.Content) == 0 {
					value.LineComment = comment.Value
				} else {
					key.LineComment = comment.Value
				}
			default:
				value.LineComment = comment.Value
			}
		case int:
			n, err = s11n.GetPath(node, comment.Path)
			if err != nil {
				return err
			}

			if n.Kind == yaml.ScalarNode {
				n.LineComment = comment.Value
			} else {
				n.HeadComment = comment.Value
			}
		default:
			return fmt.Errorf("unexpected path element '%#v'", v)
		}
	}

	return nil
}
