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

package states

import (
	"fmt"
	"sort"

	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/terraform/internal/addrs"
	"github.com/hashicorp/terraform/internal/getproviders"
)

// State is the top-level type of a Terraform state.
//
// A state should be mutated only via its accessor methods, to ensure that
// invariants are preserved.
//
// Access to State and the nested values within it is not concurrency-safe,
// so when accessing a State object concurrently it is the caller's
// responsibility to ensure that only one write is in progress at a time
// and that reads only occur when no write is in progress. The most common
// way to achieve this is to wrap the State in a SyncState and use the
// higher-level atomic operations supported by that type.
type State struct {
	// Modules contains the state for each module. The keys in this map are
	// an implementation detail and must not be used by outside callers.
	Modules map[string]*Module

	// CheckResults contains a snapshot of the statuses of checks at the
	// end of the most recent update to the state. Callers might compare
	// checks between runs to see if e.g. a previously-failing check has
	// been fixed since the last run, or similar.
	//
	// CheckResults can be nil to indicate that there are no check results
	// from the previous run at all, which is subtly different than the
	// previous run having affirmatively recorded that there are no checks
	// to run. For example, if this object was created from a state snapshot
	// created by a version of Terraform that didn't yet support checks
	// then this field will be nil.
	CheckResults *CheckResults
}

// NewState constructs a minimal empty state, containing an empty root module.
func NewState() *State {
	modules := map[string]*Module{}
	modules[addrs.RootModuleInstance.String()] = NewModule(addrs.RootModuleInstance)
	return &State{
		Modules: modules,
	}
}

// BuildState is a helper -- primarily intended for tests -- to build a state
// using imperative code against the StateSync type while still acting as
// an expression of type *State to assign into a containing struct.
func BuildState(cb func(*SyncState)) *State {
	s := NewState()
	cb(s.SyncWrapper())
	return s
}

// Empty returns true if there are no resources or populated output values
// in the receiver. In other words, if this state could be safely replaced
// with the return value of NewState and be functionally equivalent.
func (s *State) Empty() bool {
	if s == nil {
		return true
	}
	for _, ms := range s.Modules {
		if len(ms.Resources) != 0 {
			return false
		}
		if len(ms.OutputValues) != 0 {
			return false
		}
	}
	return true
}

// Module returns the state for the module with the given address, or nil if
// the requested module is not tracked in the state.
func (s *State) Module(addr addrs.ModuleInstance) *Module {
	if s == nil {
		panic("State.Module on nil *State")
	}
	return s.Modules[addr.String()]
}

// ModuleInstances returns the set of Module states that matches the given path.
func (s *State) ModuleInstances(addr addrs.Module) []*Module {
	var ms []*Module
	for _, m := range s.Modules {
		if m.Addr.Module().Equal(addr) {
			ms = append(ms, m)
		}
	}
	return ms
}

// ModuleOutputs returns all outputs for the given module call under the
// parentAddr instance.
func (s *State) ModuleOutputs(parentAddr addrs.ModuleInstance, module addrs.ModuleCall) []*OutputValue {
	var os []*OutputValue
	for _, m := range s.Modules {
		// can't get outputs from the root module
		if m.Addr.IsRoot() {
			continue
		}

		parent, call := m.Addr.Call()
		// make sure this is a descendent in the correct path
		if !parentAddr.Equal(parent) {
			continue
		}

		// and check if this is the correct child
		if call.Name != module.Name {
			continue
		}

		for _, o := range m.OutputValues {
			os = append(os, o)
		}
	}

	return os
}

// RemoveModule removes the module with the given address from the state,
// unless it is the root module. The root module cannot be deleted, and so
// this method will panic if that is attempted.
//
// Removing a module implicitly discards all of the resources, outputs and
// local values within it, and so this should usually be done only for empty
// modules. For callers accessing the state through a SyncState wrapper, modules
// are automatically pruned if they are empty after one of their contained
// elements is removed.
func (s *State) RemoveModule(addr addrs.ModuleInstance) {
	if addr.IsRoot() {
		panic("attempted to remove root module")
	}

	delete(s.Modules, addr.String())
}

// RootModule is a convenient alias for Module(addrs.RootModuleInstance).
func (s *State) RootModule() *Module {
	if s == nil {
		panic("RootModule called on nil State")
	}
	return s.Modules[addrs.RootModuleInstance.String()]
}

// EnsureModule returns the state for the module with the given address,
// creating and adding a new one if necessary.
//
// Since this might modify the state to add a new instance, it is considered
// to be a write operation.
func (s *State) EnsureModule(addr addrs.ModuleInstance) *Module {
	ms := s.Module(addr)
	if ms == nil {
		ms = NewModule(addr)
		s.Modules[addr.String()] = ms
	}
	return ms
}

// HasManagedResourceInstanceObjects returns true if there is at least one
// resource instance object (current or deposed) associated with a managed
// resource in the receiving state.
//
// A true result would suggest that just discarding this state without first
// destroying these objects could leave "dangling" objects in remote systems,
// no longer tracked by any Terraform state.
func (s *State) HasManagedResourceInstanceObjects() bool {
	if s == nil {
		return false
	}
	for _, ms := range s.Modules {
		for _, rs := range ms.Resources {
			if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
				continue
			}
			for _, is := range rs.Instances {
				if is.Current != nil || len(is.Deposed) != 0 {
					return true
				}
			}
		}
	}
	return false
}

// Resource returns the state for the resource with the given address, or nil
// if no such resource is tracked in the state.
func (s *State) Resource(addr addrs.AbsResource) *Resource {
	ms := s.Module(addr.Module)
	if ms == nil {
		return nil
	}
	return ms.Resource(addr.Resource)
}

// Resources returns the set of resources that match the given configuration path.
func (s *State) Resources(addr addrs.ConfigResource) []*Resource {
	var ret []*Resource
	for _, m := range s.ModuleInstances(addr.Module) {
		r := m.Resource(addr.Resource)
		if r != nil {
			ret = append(ret, r)
		}
	}
	return ret
}

// AllManagedResourceInstanceObjectAddrs returns a set of addresses for all of
// the leaf resource instance objects associated with managed resources that
// are tracked in this state.
//
// This result is the set of objects that would be effectively "forgotten"
// (like "terraform state rm") if this state were totally discarded, such as
// by deleting a workspace. This function is intended only for reporting
// context in error messages, such as when we reject deleting a "non-empty"
// workspace as detected by s.HasManagedResourceInstanceObjects.
//
// The ordering of the result is meaningless but consistent. DeposedKey will
// be NotDeposed (the zero value of DeposedKey) for any "current" objects.
// This method is guaranteed to return at least one item if
// s.HasManagedResourceInstanceObjects returns true for the same state, and
// to return a zero-length slice if it returns false.
func (s *State) AllResourceInstanceObjectAddrs() []struct {
	Instance   addrs.AbsResourceInstance
	DeposedKey DeposedKey
} {
	if s == nil {
		return nil
	}

	// We use an unnamed return type here just because we currently have no
	// general need to return pairs of instance address and deposed key aside
	// from this method, and this method itself is only of marginal value
	// when producing some error messages.
	//
	// If that need ends up arising more in future then it might make sense to
	// name this as addrs.AbsResourceInstanceObject, although that would require
	// moving DeposedKey into the addrs package too.
	type ResourceInstanceObject = struct {
		Instance   addrs.AbsResourceInstance
		DeposedKey DeposedKey
	}
	var ret []ResourceInstanceObject

	for _, ms := range s.Modules {
		for _, rs := range ms.Resources {
			if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
				continue
			}

			for instKey, is := range rs.Instances {
				instAddr := rs.Addr.Instance(instKey)
				if is.Current != nil {
					ret = append(ret, ResourceInstanceObject{instAddr, NotDeposed})
				}
				for deposedKey := range is.Deposed {
					ret = append(ret, ResourceInstanceObject{instAddr, deposedKey})
				}
			}
		}
	}

	sort.SliceStable(ret, func(i, j int) bool {
		objI, objJ := ret[i], ret[j]
		switch {
		case !objI.Instance.Equal(objJ.Instance):
			return objI.Instance.Less(objJ.Instance)
		default:
			return objI.DeposedKey < objJ.DeposedKey
		}
	})

	return ret
}

// ResourceInstance returns the state for the resource instance with the given
// address, or nil if no such resource is tracked in the state.
func (s *State) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance {
	if s == nil {
		panic("State.ResourceInstance on nil *State")
	}
	ms := s.Module(addr.Module)
	if ms == nil {
		return nil
	}
	return ms.ResourceInstance(addr.Resource)
}

// OutputValue returns the state for the output value with the given address,
// or nil if no such output value is tracked in the state.
func (s *State) OutputValue(addr addrs.AbsOutputValue) *OutputValue {
	ms := s.Module(addr.Module)
	if ms == nil {
		return nil
	}
	return ms.OutputValues[addr.OutputValue.Name]
}

// LocalValue returns the value of the named local value with the given address,
// or cty.NilVal if no such value is tracked in the state.
func (s *State) LocalValue(addr addrs.AbsLocalValue) cty.Value {
	ms := s.Module(addr.Module)
	if ms == nil {
		return cty.NilVal
	}
	return ms.LocalValues[addr.LocalValue.Name]
}

// ProviderAddrs returns a list of all of the provider configuration addresses
// referenced throughout the receiving state.
//
// The result is de-duplicated so that each distinct address appears only once.
func (s *State) ProviderAddrs() []addrs.AbsProviderConfig {
	if s == nil {
		return nil
	}

	m := map[string]addrs.AbsProviderConfig{}
	for _, ms := range s.Modules {
		for _, rc := range ms.Resources {
			m[rc.ProviderConfig.String()] = rc.ProviderConfig
		}
	}
	if len(m) == 0 {
		return nil
	}

	// This is mainly just so we'll get stable results for testing purposes.
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	ret := make([]addrs.AbsProviderConfig, len(keys))
	for i, key := range keys {
		ret[i] = m[key]
	}

	return ret
}

// ProviderRequirements returns a description of all of the providers that
// are required to work with the receiving state.
//
// Because the state does not track specific version information for providers,
// the requirements returned by this method will always be unconstrained.
// The result should usually be merged with a Requirements derived from the
// current configuration in order to apply some constraints.
func (s *State) ProviderRequirements() getproviders.Requirements {
	configAddrs := s.ProviderAddrs()
	ret := make(getproviders.Requirements, len(configAddrs))
	for _, configAddr := range configAddrs {
		ret[configAddr.Provider] = nil // unconstrained dependency
	}
	return ret
}

// PruneResourceHusks is a specialized method that will remove any Resource
// objects that do not contain any instances, even if they have an EachMode.
//
// This should generally be used only after a "terraform destroy" operation,
// to finalize the cleanup of the state. It is not correct to use this after
// other operations because if a resource has "count = 0" or "for_each" over
// an empty collection then we want to retain it in the state so that references
// to it, particularly in "strange" contexts like "terraform console", can be
// properly resolved.
//
// This method MUST NOT be called concurrently with other readers and writers
// of the receiving state.
func (s *State) PruneResourceHusks() {
	for _, m := range s.Modules {
		m.PruneResourceHusks()
		if len(m.Resources) == 0 && !m.Addr.IsRoot() {
			s.RemoveModule(m.Addr)
		}
	}
}

// SyncWrapper returns a SyncState object wrapping the receiver.
func (s *State) SyncWrapper() *SyncState {
	return &SyncState{
		state: s,
	}
}

// MoveAbsResource moves the given src AbsResource's current state to the new
// dst address. This will panic if the src AbsResource does not exist in state,
// or if there is already a resource at the dst address. It is the caller's
// responsibility to verify the validity of the move (for example, that the src
// and dst are compatible types).
func (s *State) MoveAbsResource(src, dst addrs.AbsResource) {
	// verify that the src address exists and the dst address does not
	rs := s.Resource(src)
	if rs == nil {
		panic(fmt.Sprintf("no state for src address %s", src.String()))
	}

	ds := s.Resource(dst)
	if ds != nil {
		panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
	}

	ms := s.Module(src.Module)
	ms.RemoveResource(src.Resource)

	// Remove the module if it is empty (and not root) after removing the
	// resource.
	if !ms.Addr.IsRoot() && ms.empty() {
		s.RemoveModule(src.Module)
	}

	// Update the address before adding it to the state
	rs.Addr = dst
	s.EnsureModule(dst.Module).Resources[dst.Resource.String()] = rs
}

// MaybeMoveAbsResource moves the given src AbsResource's current state to the
// new dst address. This function will succeed if both the src address does not
// exist in state and the dst address does; the return value indicates whether
// or not the move occurred. This function will panic if either the src does not
// exist or the dst does exist (but not both).
func (s *State) MaybeMoveAbsResource(src, dst addrs.AbsResource) bool {
	// Get the source and destinatation addresses from state.
	rs := s.Resource(src)
	ds := s.Resource(dst)

	// Normal case: the src exists in state, dst does not
	if rs != nil && ds == nil {
		s.MoveAbsResource(src, dst)
		return true
	}

	if rs == nil && ds != nil {
		// The source is not in state, the destination is. This is not
		// guaranteed to be idempotent since we aren't tracking exact moves, but
		// it's useful information for the caller.
		return false
	} else {
		panic("invalid move")
	}
}

// MoveAbsResourceInstance moves the given src AbsResourceInstance's current state to
// the new dst address. This will panic if the src AbsResourceInstance does not
// exist in state, or if there is already a resource at the dst address. It is
// the caller's responsibility to verify the validity of the move (for example,
// that the src and dst are compatible types).
func (s *State) MoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) {
	srcInstanceState := s.ResourceInstance(src)
	if srcInstanceState == nil {
		panic(fmt.Sprintf("no state for src address %s", src.String()))
	}

	dstInstanceState := s.ResourceInstance(dst)
	if dstInstanceState != nil {
		panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
	}

	srcResourceState := s.Resource(src.ContainingResource())
	srcProviderAddr := srcResourceState.ProviderConfig
	dstResourceAddr := dst.ContainingResource()

	// Remove the source resource instance from the module's state, and then the
	// module if empty.
	ms := s.Module(src.Module)
	ms.ForgetResourceInstanceAll(src.Resource)
	if !ms.Addr.IsRoot() && ms.empty() {
		s.RemoveModule(src.Module)
	}

	dstModule := s.EnsureModule(dst.Module)

	// See if there is already a resource we can add this instance to.
	dstResourceState := s.Resource(dstResourceAddr)
	if dstResourceState == nil {
		// If we're moving to an address without an index then that
		// suggests the user's intent is to establish both the
		// resource and the instance at the same time (since the
		// address covers both). If there's an index in the
		// target then allow creating the new instance here.
		dstModule.SetResourceProvider(
			dstResourceAddr.Resource,
			srcProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
		)
		dstResourceState = dstModule.Resource(dstResourceAddr.Resource)
	}

	dstResourceState.Instances[dst.Resource.Key] = srcInstanceState
}

// MaybeMoveAbsResourceInstance moves the given src AbsResourceInstance's
// current state to the new dst address. This function will succeed if both the
// src address does not exist in state and the dst address does; the return
// value indicates whether or not the move occured. This function will panic if
// either the src does not exist or the dst does exist (but not both).
func (s *State) MaybeMoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) bool {
	// get the src and dst resource instances from state
	rs := s.ResourceInstance(src)
	ds := s.ResourceInstance(dst)

	// Normal case: the src exists in state, dst does not
	if rs != nil && ds == nil {
		s.MoveAbsResourceInstance(src, dst)
		return true
	}

	if rs == nil && ds != nil {
		// The source is not in state, the destination is. This is not
		// guaranteed to be idempotent since we aren't tracking exact moves, but
		// it's useful information.
		return false
	} else {
		panic("invalid move")
	}
}

// MoveModuleInstance moves the given src ModuleInstance's current state to the
// new dst address. This will panic if the src ModuleInstance does not
// exist in state, or if there is already a resource at the dst address. It is
// the caller's responsibility to verify the validity of the move.
func (s *State) MoveModuleInstance(src, dst addrs.ModuleInstance) {
	if src.IsRoot() || dst.IsRoot() {
		panic("cannot move to or from root module")
	}

	srcMod := s.Module(src)
	if srcMod == nil {
		panic(fmt.Sprintf("no state for src module %s", src.String()))
	}

	dstMod := s.Module(dst)
	if dstMod != nil {
		panic(fmt.Sprintf("dst module %s already exists in state", dst.String()))
	}

	s.RemoveModule(src)

	srcMod.Addr = dst
	s.EnsureModule(dst)
	s.Modules[dst.String()] = srcMod

	// Update any Resource's addresses.
	if srcMod.Resources != nil {
		for _, r := range srcMod.Resources {
			r.Addr.Module = dst
		}
	}

	// Update any OutputValues's addresses.
	if srcMod.OutputValues != nil {
		for _, ov := range srcMod.OutputValues {
			ov.Addr.Module = dst
		}
	}
}

// MaybeMoveModuleInstance moves the given src ModuleInstance's current state to
// the new dst address. This function will succeed if both the src address does
// not exist in state and the dst address does; the return value indicates
// whether or not the move occured. This function will panic if either the src
// does not exist or the dst does exist (but not both).
func (s *State) MaybeMoveModuleInstance(src, dst addrs.ModuleInstance) bool {
	if src.IsRoot() || dst.IsRoot() {
		panic("cannot move to or from root module")
	}

	srcMod := s.Module(src)
	dstMod := s.Module(dst)

	// Normal case: the src exists in state, dst does not
	if srcMod != nil && dstMod == nil {
		s.MoveModuleInstance(src, dst)
		return true
	}

	if srcMod == nil || src.IsRoot() && dstMod != nil {
		// The source is not in state, the destination is. This is not
		// guaranteed to be idempotent since we aren't tracking exact moves, but
		// it's useful information.
		return false
	} else {
		panic("invalid move")
	}
}

// MoveModule takes a source and destination addrs.Module address, and moves all
// state Modules which are contained by the src address to the new address.
func (s *State) MoveModule(src, dst addrs.AbsModuleCall) {
	if src.Module.IsRoot() || dst.Module.IsRoot() {
		panic("cannot move to or from root module")
	}

	// Modules only exist as ModuleInstances in state, so we need to check each
	// state Module and see if it is contained by the src address to get a full
	// list of modules to move.
	var srcMIs []*Module
	for _, module := range s.Modules {
		if !module.Addr.IsRoot() {
			if src.Module.TargetContains(module.Addr) {
				srcMIs = append(srcMIs, module)
			}
		}
	}

	if len(srcMIs) == 0 {
		panic(fmt.Sprintf("no matching module instances found for src module %s", src.String()))
	}

	for _, ms := range srcMIs {
		newInst := make(addrs.ModuleInstance, len(ms.Addr))
		copy(newInst, ms.Addr)
		if ms.Addr.IsDeclaredByCall(src) {
			// Easy case: we just need to update the last step with the new name
			newInst[len(newInst)-1].Name = dst.Call.Name
		} else {
			// Trickier: this Module is a submodule. we need to find and update
			// only that appropriate step
			for s := range newInst {
				if newInst[s].Name == src.Call.Name {
					newInst[s].Name = dst.Call.Name
				}
			}
		}
		s.MoveModuleInstance(ms.Addr, newInst)
	}
}
