package terraform

import (
	"context"
	"fmt"
	"strings"

	"github.com/databricks/cli/bundle"
	"github.com/databricks/cli/libs/cmdio"
	"github.com/databricks/cli/libs/diag"
	"github.com/fatih/color"
	"github.com/hashicorp/terraform-exec/tfexec"
	tfjson "github.com/hashicorp/terraform-json"
)

type PlanResourceChange struct {
	ResourceType string `json:"resource_type"`
	Action       string `json:"action"`
	ResourceName string `json:"resource_name"`
}

func (c *PlanResourceChange) String() string {
	result := strings.Builder{}
	switch c.Action {
	case "delete":
		result.WriteString("  delete ")
	default:
		result.WriteString(c.Action + " ")
	}
	switch c.ResourceType {
	case "databricks_job":
		result.WriteString("job ")
	case "databricks_pipeline":
		result.WriteString("pipeline ")
	default:
		result.WriteString(c.ResourceType + " ")
	}
	result.WriteString(c.ResourceName)
	return result.String()
}

func (c *PlanResourceChange) IsInplaceSupported() bool {
	return false
}

func logDestroyPlan(ctx context.Context, changes []*tfjson.ResourceChange) error {
	cmdio.LogString(ctx, "The following resources will be removed:")
	for _, c := range changes {
		if c.Change.Actions.Delete() {
			cmdio.Log(ctx, &PlanResourceChange{
				ResourceType: c.Type,
				Action:       "delete",
				ResourceName: c.Name,
			})
		}
	}
	return nil
}

type destroy struct{}

func (w *destroy) Name() string {
	return "terraform.Destroy"
}

func (w *destroy) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
	// return early if plan is empty
	if b.Plan.IsEmpty {
		cmdio.LogString(ctx, "No resources to destroy in plan. Skipping destroy!")
		return nil
	}

	tf := b.Terraform
	if tf == nil {
		return diag.Errorf("terraform not initialized")
	}

	// read plan file
	plan, err := tf.ShowPlanFile(ctx, b.Plan.Path)
	if err != nil {
		return diag.FromErr(err)
	}

	// print the resources that will be destroyed
	err = logDestroyPlan(ctx, plan.ResourceChanges)
	if err != nil {
		return diag.FromErr(err)
	}

	// Ask for confirmation, if needed
	if !b.Plan.ConfirmApply {
		red := color.New(color.FgRed).SprintFunc()
		b.Plan.ConfirmApply, err = cmdio.AskYesOrNo(ctx, fmt.Sprintf("\nThis will permanently %s resources! Proceed?", red("destroy")))
		if err != nil {
			return diag.FromErr(err)
		}
	}

	// return if confirmation was not provided
	if !b.Plan.ConfirmApply {
		return nil
	}

	if b.Plan.Path == "" {
		return diag.Errorf("no plan found")
	}

	cmdio.LogString(ctx, "Starting to destroy resources")

	// Apply terraform according to the computed destroy plan
	err = tf.Apply(ctx, tfexec.DirOrPlan(b.Plan.Path))
	if err != nil {
		return diag.Errorf("terraform destroy: %v", err)
	}

	cmdio.LogString(ctx, "Successfully destroyed resources!")
	return nil
}

// Destroy returns a [bundle.Mutator] that runs the conceptual equivalent of
// `terraform destroy ./plan` from the bundle's ephemeral working directory for Terraform.
func Destroy() bundle.Mutator {
	return &destroy{}
}