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

package tfexec

import (
	"context"
	"fmt"
	"os/exec"
	"strings"
)

type graphConfig struct {
	plan       string
	drawCycles bool
	graphType  string
}

var defaultGraphOptions = graphConfig{}

type GraphOption interface {
	configureGraph(*graphConfig)
}

func (opt *GraphPlanOption) configureGraph(conf *graphConfig) {
	conf.plan = opt.file
}

func (opt *DrawCyclesOption) configureGraph(conf *graphConfig) {
	conf.drawCycles = opt.drawCycles
}

func (opt *GraphTypeOption) configureGraph(conf *graphConfig) {
	conf.graphType = opt.graphType
}

func (tf *Terraform) Graph(ctx context.Context, opts ...GraphOption) (string, error) {
	graphCmd, err := tf.graphCmd(ctx, opts...)
	if err != nil {
		return "", err
	}
	var outBuf strings.Builder
	graphCmd.Stdout = &outBuf
	err = tf.runTerraformCmd(ctx, graphCmd)
	if err != nil {
		return "", err
	}

	return outBuf.String(), nil

}

func (tf *Terraform) graphCmd(ctx context.Context, opts ...GraphOption) (*exec.Cmd, error) {
	c := defaultGraphOptions

	for _, o := range opts {
		o.configureGraph(&c)
	}

	args := []string{"graph"}

	if c.plan != "" {
		// plan was a positional argument prior to Terraform 0.15.0. Ensure proper use by checking version.
		if err := tf.compatible(ctx, tf0_15_0, nil); err == nil {
			args = append(args, "-plan="+c.plan)
		} else {
			args = append(args, c.plan)
		}
	}

	if c.drawCycles {
		err := tf.compatible(ctx, tf0_5_0, nil)
		if err != nil {
			return nil, fmt.Errorf("-draw-cycles was first introduced in Terraform 0.5.0: %w", err)
		}
		args = append(args, "-draw-cycles")
	}

	if c.graphType != "" {
		err := tf.compatible(ctx, tf0_8_0, nil)
		if err != nil {
			return nil, fmt.Errorf("-graph-type was first introduced in Terraform 0.8.0: %w", err)
		}
		args = append(args, "-type="+c.graphType)
	}

	return tf.buildTerraformCmd(ctx, nil, args...), nil
}
