package tfdiags

import (
	"github.com/hashicorp/hcl/v2"
)

// hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic
type hclDiagnostic struct {
	diag *hcl.Diagnostic
}

var _ Diagnostic = hclDiagnostic{}

func (d hclDiagnostic) Severity() Severity {
	switch d.diag.Severity {
	case hcl.DiagWarning:
		return Warning
	default:
		return Error
	}
}

func (d hclDiagnostic) Description() Description {
	return Description{
		Summary: d.diag.Summary,
		Detail:  d.diag.Detail,
	}
}

func (d hclDiagnostic) Source() Source {
	var ret Source
	if d.diag.Subject != nil {
		rng := SourceRangeFromHCL(*d.diag.Subject)
		ret.Subject = &rng
	}
	if d.diag.Context != nil {
		rng := SourceRangeFromHCL(*d.diag.Context)
		ret.Context = &rng
	}
	return ret
}

func (d hclDiagnostic) FromExpr() *FromExpr {
	if d.diag.Expression == nil || d.diag.EvalContext == nil {
		return nil
	}
	return &FromExpr{
		Expression:  d.diag.Expression,
		EvalContext: d.diag.EvalContext,
	}
}

func (d hclDiagnostic) ExtraInfo() interface{} {
	return d.diag.Extra
}

// SourceRangeFromHCL constructs a SourceRange from the corresponding range
// type within the HCL package.
func SourceRangeFromHCL(hclRange hcl.Range) SourceRange {
	return SourceRange{
		Filename: hclRange.Filename,
		Start: SourcePos{
			Line:   hclRange.Start.Line,
			Column: hclRange.Start.Column,
			Byte:   hclRange.Start.Byte,
		},
		End: SourcePos{
			Line:   hclRange.End.Line,
			Column: hclRange.End.Column,
			Byte:   hclRange.End.Byte,
		},
	}
}

// ToHCL constructs a HCL Range from the receiving SourceRange. This is the
// opposite of SourceRangeFromHCL.
func (r SourceRange) ToHCL() hcl.Range {
	return hcl.Range{
		Filename: r.Filename,
		Start: hcl.Pos{
			Line:   r.Start.Line,
			Column: r.Start.Column,
			Byte:   r.Start.Byte,
		},
		End: hcl.Pos{
			Line:   r.End.Line,
			Column: r.End.Column,
			Byte:   r.End.Byte,
		},
	}
}

// ToHCL constructs a hcl.Diagnostics containing the same diagnostic messages
// as the receiving tfdiags.Diagnostics.
//
// This conversion preserves the data that HCL diagnostics are able to
// preserve but would be lossy in a round trip from tfdiags to HCL and then
// back to tfdiags, because it will lose the specific type information of
// the source diagnostics. In most cases this will not be a significant
// problem, but could produce an awkward result in some special cases such
// as converting the result of ConsolidateWarnings, which will force the
// resulting warning groups to be flattened early.
func (diags Diagnostics) ToHCL() hcl.Diagnostics {
	if len(diags) == 0 {
		return nil
	}
	ret := make(hcl.Diagnostics, len(diags))
	for i, diag := range diags {
		severity := diag.Severity()
		desc := diag.Description()
		source := diag.Source()
		fromExpr := diag.FromExpr()

		hclDiag := &hcl.Diagnostic{
			Summary:  desc.Summary,
			Detail:   desc.Detail,
			Severity: severity.ToHCL(),
		}
		if source.Subject != nil {
			hclDiag.Subject = source.Subject.ToHCL().Ptr()
		}
		if source.Context != nil {
			hclDiag.Context = source.Context.ToHCL().Ptr()
		}
		if fromExpr != nil {
			hclDiag.Expression = fromExpr.Expression
			hclDiag.EvalContext = fromExpr.EvalContext
		}

		ret[i] = hclDiag
	}
	return ret
}
