// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1

package arguments

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/hashicorp/terraform/internal/depsfile"
	"github.com/hashicorp/terraform/internal/tfdiags"
)

const lockFileName = depsfile.LockFilePath // .terraform.lock.hcl

// StateMigrate represents the command-line arguments for the state migrate command.
type StateMigrate struct {
	SourceLockFilePath      string
	DestinationLockFilePath string
	Upgrade                 bool
	ForceCopy               bool
	InputEnabled            bool

	ViewType ViewType
}

// ParseStateMigrate processes CLI arguments, returning a StateMigrate value and
// diagnostics. If errors are encountered, a StateMigrate value is still returned
// representing the best effort interpretation of the arguments.
func ParseStateMigrate(args []string) (*StateMigrate, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics
	migrate := &StateMigrate{}

	var srcLockFilePath, dstLockFilePath string
	var upgrade, inputEnabled, forceCopy, json bool
	cmdFlags := defaultFlagSet("state migrate")
	cmdFlags.StringVar(&srcLockFilePath, "source-provider-lock-file", "", "Path to a provider lock file for the source provider.")
	cmdFlags.StringVar(&dstLockFilePath, "destination-provider-lock-file", "", "Path to a provider lock file for the destination provider.")
	cmdFlags.BoolVar(&upgrade, "upgrade", false, "Trigger upgrade of the provider.")
	cmdFlags.BoolVar(&inputEnabled, "input", true, "Enable input for interactive prompts.")
	cmdFlags.BoolVar(&forceCopy, "force-copy", false, "Suppress and auto-approve prompts about copying state data. Enables state migrations when interactive prompts are disabled via -input=false.")
	cmdFlags.BoolVar(&json, "json", false, "Enable JSON output.")

	if err := cmdFlags.Parse(args); err != nil {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Failed to parse command-line flags",
			err.Error(),
		))
		return migrate, diags
	}

	migrate.Upgrade = upgrade
	migrate.InputEnabled = inputEnabled
	migrate.ForceCopy = forceCopy

	if inputEnabled {
		// lock file paths are only to be used in automation
		if srcLockFilePath != "" {
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Conflicting command-line flags provided",
				"-source-provider-lock-file cannot be used outside of automation (with -input=true)",
			))
		}
		if dstLockFilePath != "" {
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Conflicting command-line flags provided",
				"-destination-provider-lock-file cannot be used outside of automation (with -input=true)",
			))
		}

		// JSON output is only to be used in automation, as input cannot be received
		if json {
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Conflicting command-line flags provided",
				"-json cannot be used outside of automation (with -input=true)",
			))
		}
	}

	if srcLockFilePath != "" {
		// If a file is supplied via flag, it must exist.
		if _, err := os.Stat(srcLockFilePath); err != nil {
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Unreadable source provider lock file",
				fmt.Sprintf("%q: %s", srcLockFilePath, err.Error()),
			))
		}

		srcFilename := filepath.Base(srcLockFilePath)
		if srcFilename != lockFileName {
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Invalid source-provider-lock-file",
				fmt.Sprintf("Expected lock file name to be %s, got: %s", lockFileName, srcFilename),
			))
		}

		migrate.SourceLockFilePath = srcLockFilePath
	}

	if dstLockFilePath != "" {
		// If a file is supplied via flag, it must exist.
		if _, err := os.Stat(dstLockFilePath); err != nil {
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Unreadable destination provider lock file",
				fmt.Sprintf("%q: %s", dstLockFilePath, err.Error()),
			))
		}

		dstFilename := filepath.Base(dstLockFilePath)
		if dstFilename != lockFileName {
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Invalid destination-provider-lock-file",
				fmt.Sprintf("Expected lock file name to be %s, got: %s", lockFileName, dstFilename),
			))
		}
		migrate.DestinationLockFilePath = dstLockFilePath
	}

	if json {
		migrate.ViewType = ViewJSON
	} else {
		migrate.ViewType = ViewHuman
	}

	return migrate, diags
}
