package main

import (
	"context"
	"fmt"
	"os"
	"testing"
	"time"

	expect "github.com/Netflix/go-expect"
	tfe "github.com/hashicorp/go-tfe"
	"github.com/hashicorp/go-uuid"
	goversion "github.com/hashicorp/go-version"
	tfversion "github.com/hashicorp/terraform/version"
)

const (
	// We need to give the console enough time to hear back.
	// 1 minute was too short in some cases, so this gives it ample time.
	expectConsoleTimeout = 3 * time.Minute
)

type tfCommand struct {
	command           []string
	expectedCmdOutput string
	expectError       bool
	userInput         []string
	postInputOutput   []string
}

type operationSets struct {
	commands []tfCommand
	prep     func(t *testing.T, orgName, dir string)
}

type testCases map[string]struct {
	operations  []operationSets
	validations func(t *testing.T, orgName string)
}

func defaultOpts() []expect.ConsoleOpt {
	opts := []expect.ConsoleOpt{
		expect.WithDefaultTimeout(expectConsoleTimeout),
	}
	if verboseMode {
		opts = append(opts, expect.WithStdout(os.Stdout))
	}
	return opts
}

func createOrganization(t *testing.T) (*tfe.Organization, func()) {
	ctx := context.Background()
	org, err := tfeClient.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
		Name:                  tfe.String("tst-" + randomString(t)),
		Email:                 tfe.String(fmt.Sprintf("%s@tfe.local", randomString(t))),
		CostEstimationEnabled: tfe.Bool(false),
	})
	if err != nil {
		t.Fatal(err)
	}

	_, err = tfeClient.Admin.Organizations.Update(ctx, org.Name, tfe.AdminOrganizationUpdateOptions{
		AccessBetaTools: tfe.Bool(true),
	})
	if err != nil {
		t.Fatal(err)
	}

	return org, func() {
		if err := tfeClient.Organizations.Delete(ctx, org.Name); err != nil {
			t.Errorf("Error destroying organization! WARNING: Dangling resources\n"+
				"may exist! The full error is shown below.\n\n"+
				"Organization: %s\nError: %s", org.Name, err)
		}
	}
}

func createWorkspace(t *testing.T, orgName string, wOpts tfe.WorkspaceCreateOptions) *tfe.Workspace {
	ctx := context.Background()
	w, err := tfeClient.Workspaces.Create(ctx, orgName, wOpts)
	if err != nil {
		t.Fatal(err)
	}

	return w
}

func getWorkspace(workspaces []*tfe.Workspace, workspace string) (*tfe.Workspace, bool) {
	for _, ws := range workspaces {
		if ws.Name == workspace {
			return ws, false
		}
	}
	return nil, true
}

func randomString(t *testing.T) string {
	v, err := uuid.GenerateUUID()
	if err != nil {
		t.Fatal(err)
	}
	return v
}

func terraformConfigLocalBackend() string {
	return `
terraform {
  backend "local" {
  }
}

output "val" {
  value = "${terraform.workspace}"
}
`
}

func terraformConfigRemoteBackendName(org, name string) string {
	return fmt.Sprintf(`
terraform {
  backend "remote" {
    hostname = "%s"
    organization = "%s"

    workspaces {
      name = "%s"
    }
  }
}

output "val" {
  value = "${terraform.workspace}"
}
`, tfeHostname, org, name)
}

func terraformConfigRemoteBackendPrefix(org, prefix string) string {
	return fmt.Sprintf(`
terraform {
  backend "remote" {
    hostname = "%s"
    organization = "%s"

    workspaces {
      prefix = "%s"
    }
  }
}

output "val" {
  value = "${terraform.workspace}"
}
`, tfeHostname, org, prefix)
}

func terraformConfigCloudBackendTags(org, tag string) string {
	return fmt.Sprintf(`
terraform {
  cloud {
    hostname = "%s"
    organization = "%s"

    workspaces {
      tags = ["%s"]
    }
  }
}

output "tag_val" {
  value = "%s"
}
`, tfeHostname, org, tag, tag)
}

func terraformConfigCloudBackendName(org, name string) string {
	return fmt.Sprintf(`
terraform {
  cloud {
    hostname = "%s"
    organization = "%s"

    workspaces {
      name = "%s"
    }
  }
}

output "val" {
  value = "${terraform.workspace}"
}
`, tfeHostname, org, name)
}

func terraformConfigCloudBackendOmitOrg(workspaceName string) string {
	return fmt.Sprintf(`
terraform {
  cloud {
    hostname = "%s"

	workspaces {
	  name = "%s"
	}
  }
}

output "val" {
  value = "${terraform.workspace}"
}
`, tfeHostname, workspaceName)
}

func terraformConfigCloudBackendOmitWorkspaces(orgName string) string {
	return fmt.Sprintf(`
terraform {
  cloud {
    hostname = "%s"
	organization = "%s"
  }
}

output "val" {
  value = "${terraform.workspace}"
}
`, tfeHostname, orgName)
}

func terraformConfigCloudBackendOmitConfig() string {
	return `
terraform {
  cloud {}
}

output "val" {
  value = "${terraform.workspace}"
}
`
}

func writeMainTF(t *testing.T, block string, dir string) {
	f, err := os.Create(fmt.Sprintf("%s/main.tf", dir))
	if err != nil {
		t.Fatal(err)
	}
	_, err = f.WriteString(block)
	if err != nil {
		t.Fatal(err)
	}
	f.Close()
}

// The e2e tests rely on the fact that the terraform version in TFC/E is able to
// run the `cloud` configuration block, which is available in 1.1 and will
// continue to be available in later versions. So this function checks that
// there is a version that is >= 1.1.
func skipWithoutRemoteTerraformVersion(t *testing.T) {
	version := tfversion.Version
	baseVersion, err := goversion.NewVersion(version)
	if err != nil {
		t.Fatalf(fmt.Sprintf("Error instantiating go-version for %s", version))
	}
	opts := &tfe.AdminTerraformVersionsListOptions{
		ListOptions: tfe.ListOptions{
			PageNumber: 1,
			PageSize:   100,
		},
	}
	hasVersion := false

findTfVersion:
	for {
		// TODO: update go-tfe Read() to retrieve a terraform version by name.
		// Currently you can only retrieve by ID.
		tfVersionList, err := tfeClient.Admin.TerraformVersions.List(context.Background(), opts)
		if err != nil {
			t.Fatalf("Could not retrieve list of terraform versions: %v", err)
		}
		for _, item := range tfVersionList.Items {
			availableVersion, err := goversion.NewVersion(item.Version)
			if err != nil {
				t.Logf("Error instantiating go-version for %s", item.Version)
				continue
			}
			if availableVersion.Core().GreaterThanOrEqual(baseVersion.Core()) {
				hasVersion = true
				break findTfVersion
			}
		}

		// Exit the loop when we've seen all pages.
		if tfVersionList.CurrentPage >= tfVersionList.TotalPages {
			break
		}

		// Update the page number to get the next page.
		opts.PageNumber = tfVersionList.NextPage
	}

	if !hasVersion {
		t.Skipf("Skipping test because TFC/E does not have current Terraform version to test with (%s)", version)
	}
}
