package renderers

import (
	"bytes"
	"fmt"
	"sort"

	"github.com/hashicorp/terraform/internal/command/jsonformat/computed"

	"github.com/hashicorp/terraform/internal/plans"
)

var (
	_ computed.DiffRenderer = (*blockRenderer)(nil)

	importantAttributes = []string{
		"id",
		"name",
		"tags",
	}
)

func importantAttribute(attr string) bool {
	for _, attribute := range importantAttributes {
		if attribute == attr {
			return true
		}
	}
	return false
}

func Block(attributes map[string]computed.Diff, blocks Blocks) computed.DiffRenderer {
	return &blockRenderer{
		attributes: attributes,
		blocks:     blocks,
	}
}

type blockRenderer struct {
	NoWarningsRenderer

	attributes map[string]computed.Diff
	blocks     Blocks
}

func (renderer blockRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
	if len(renderer.attributes) == 0 && len(renderer.blocks.GetAllKeys()) == 0 {
		return fmt.Sprintf("{}%s", forcesReplacement(diff.Replace, opts))
	}

	unchangedAttributes := 0
	unchangedBlocks := 0

	maximumAttributeKeyLen := 0
	var attributeKeys []string
	escapedAttributeKeys := make(map[string]string)
	for key := range renderer.attributes {
		attributeKeys = append(attributeKeys, key)
		escapedKey := EnsureValidAttributeName(key)
		escapedAttributeKeys[key] = escapedKey
		if maximumAttributeKeyLen < len(escapedKey) {
			maximumAttributeKeyLen = len(escapedKey)
		}
	}
	sort.Strings(attributeKeys)

	importantAttributeOpts := opts.Clone()
	importantAttributeOpts.ShowUnchangedChildren = true

	attributeOpts := opts.Clone()

	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts)))
	for _, key := range attributeKeys {
		attribute := renderer.attributes[key]
		if importantAttribute(key) {

			// Always display the important attributes.
			for _, warning := range attribute.WarningsHuman(indent+1, importantAttributeOpts) {
				buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
			}
			buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, importantAttributeOpts), maximumAttributeKeyLen, key, attribute.RenderHuman(indent+1, importantAttributeOpts)))
			continue
		}
		if attribute.Action == plans.NoOp && !opts.ShowUnchangedChildren {
			unchangedAttributes++
			continue
		}

		for _, warning := range attribute.WarningsHuman(indent+1, opts) {
			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
		}
		buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, attributeOpts), maximumAttributeKeyLen, escapedAttributeKeys[key], attribute.RenderHuman(indent+1, attributeOpts)))
	}

	if unchangedAttributes > 0 {
		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("attribute", unchangedAttributes, opts)))
	}

	blockKeys := renderer.blocks.GetAllKeys()
	for _, key := range blockKeys {

		foundChangedBlock := false
		renderBlock := func(diff computed.Diff, mapKey string, opts computed.RenderHumanOpts) {

			creatingSensitiveValue := diff.Action == plans.Create && renderer.blocks.AfterSensitiveBlocks[key]
			deletingSensitiveValue := diff.Action == plans.Delete && renderer.blocks.BeforeSensitiveBlocks[key]
			modifyingSensitiveValue := (diff.Action == plans.Update || diff.Action == plans.NoOp) && (renderer.blocks.AfterSensitiveBlocks[key] || renderer.blocks.BeforeSensitiveBlocks[key])

			if creatingSensitiveValue || deletingSensitiveValue || modifyingSensitiveValue {
				// Intercept the renderer here if the sensitive data was set
				// across all the blocks instead of individually.
				action := diff.Action
				if diff.Action == plans.NoOp && renderer.blocks.BeforeSensitiveBlocks[key] != renderer.blocks.AfterSensitiveBlocks[key] {
					action = plans.Update
				}

				diff = computed.NewDiff(SensitiveBlock(diff, renderer.blocks.BeforeSensitiveBlocks[key], renderer.blocks.AfterSensitiveBlocks[key]), action, diff.Replace)
			}

			if diff.Action == plans.NoOp && !opts.ShowUnchangedChildren {
				unchangedBlocks++
				return
			}

			if !foundChangedBlock && len(renderer.attributes) > 0 {
				// We always want to put an extra new line between the
				// attributes and blocks, and between groups of blocks.
				buf.WriteString("\n")
				foundChangedBlock = true
			}

			// If the force replacement metadata was set for every entry in the
			// block we need to override that here. Our child blocks will only
			// know about the replace function if it was set on them
			// specifically, and not if it was set for all the blocks.
			blockOpts := opts.Clone()
			blockOpts.OverrideForcesReplacement = renderer.blocks.ReplaceBlocks[key]

			for _, warning := range diff.WarningsHuman(indent+1, blockOpts) {
				buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
			}
			buf.WriteString(fmt.Sprintf("%s%s%s%s %s\n", formatIndent(indent+1), writeDiffActionSymbol(diff.Action, blockOpts), EnsureValidAttributeName(key), mapKey, diff.RenderHuman(indent+1, blockOpts)))

		}

		switch {
		case renderer.blocks.IsSingleBlock(key):
			renderBlock(renderer.blocks.SingleBlocks[key], "", opts)
		case renderer.blocks.IsMapBlock(key):
			var keys []string
			for key := range renderer.blocks.MapBlocks[key] {
				keys = append(keys, key)
			}
			sort.Strings(keys)

			for _, innerKey := range keys {
				renderBlock(renderer.blocks.MapBlocks[key][innerKey], fmt.Sprintf(" %q", innerKey), opts)
			}
		case renderer.blocks.IsSetBlock(key):

			setOpts := opts.Clone()
			setOpts.OverrideForcesReplacement = diff.Replace

			for _, block := range renderer.blocks.SetBlocks[key] {
				renderBlock(block, "", opts)
			}
		case renderer.blocks.IsListBlock(key):
			for _, block := range renderer.blocks.ListBlocks[key] {
				renderBlock(block, "", opts)
			}
		}
	}

	if unchangedBlocks > 0 {
		buf.WriteString(fmt.Sprintf("\n%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("block", unchangedBlocks, opts)))
	}

	buf.WriteString(fmt.Sprintf("%s%s}", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts)))
	return buf.String()
}
