// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package renderers

import (
	"sort"

	"github.com/opentofu/opentofu/internal/command/jsonformat/computed"
)

// Blocks is a helper struct for collating the different kinds of blocks in a
// simple way for rendering.
type Blocks struct {
	SingleBlocks map[string]computed.Diff
	ListBlocks   map[string][]computed.Diff
	SetBlocks    map[string][]computed.Diff
	MapBlocks    map[string]map[string]computed.Diff

	// ReplaceBlocks and Before/AfterSensitiveBlocks carry forward the
	// information about an entire group of blocks (eg. if all the blocks for a
	// given list block are sensitive that isn't captured in the individual
	// blocks as they are processed independently). These maps allow the
	// renderer to check the metadata on the overall groups and respond
	// accordingly.

	ReplaceBlocks         map[string]bool
	BeforeSensitiveBlocks map[string]bool
	AfterSensitiveBlocks  map[string]bool
}

func (blocks *Blocks) GetAllKeys() []string {
	var keys []string
	for key := range blocks.SingleBlocks {
		keys = append(keys, key)
	}
	for key := range blocks.ListBlocks {
		keys = append(keys, key)
	}
	for key := range blocks.SetBlocks {
		keys = append(keys, key)
	}
	for key := range blocks.MapBlocks {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return keys
}

func (blocks *Blocks) IsSingleBlock(key string) bool {
	_, ok := blocks.SingleBlocks[key]
	return ok
}

func (blocks *Blocks) IsListBlock(key string) bool {
	_, ok := blocks.ListBlocks[key]
	return ok
}

func (blocks *Blocks) IsMapBlock(key string) bool {
	_, ok := blocks.MapBlocks[key]
	return ok
}

func (blocks *Blocks) IsSetBlock(key string) bool {
	_, ok := blocks.SetBlocks[key]
	return ok
}

func (blocks *Blocks) AddSingleBlock(key string, diff computed.Diff, replace, beforeSensitive, afterSensitive bool) {
	blocks.SingleBlocks[key] = diff
	blocks.ReplaceBlocks[key] = replace
	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
	blocks.AfterSensitiveBlocks[key] = afterSensitive
}

func (blocks *Blocks) AddAllListBlock(key string, diffs []computed.Diff, replace, beforeSensitive, afterSensitive bool) {
	blocks.ListBlocks[key] = diffs
	blocks.ReplaceBlocks[key] = replace
	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
	blocks.AfterSensitiveBlocks[key] = afterSensitive
}

func (blocks *Blocks) AddAllSetBlock(key string, diffs []computed.Diff, replace, beforeSensitive, afterSensitive bool) {
	blocks.SetBlocks[key] = diffs
	blocks.ReplaceBlocks[key] = replace
	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
	blocks.AfterSensitiveBlocks[key] = afterSensitive
}

func (blocks *Blocks) AddAllMapBlocks(key string, diffs map[string]computed.Diff, replace, beforeSensitive, afterSensitive bool) {
	blocks.MapBlocks[key] = diffs
	blocks.ReplaceBlocks[key] = replace
	blocks.BeforeSensitiveBlocks[key] = beforeSensitive
	blocks.AfterSensitiveBlocks[key] = afterSensitive
}
