package launch

import (
	"testing"

	"github.com/stretchr/testify/assert"
	fly "github.com/superfly/fly-go"
	"github.com/superfly/flyctl/internal/appconfig"
	"github.com/superfly/flyctl/internal/command/launch/plan"
)

func TestWillCreateManagedPostgresCluster(t *testing.T) {
	tests := []struct {
		name     string
		postgres plan.PostgresPlan
		planStep string
		expected bool
	}{
		{
			name: "new managed postgres",
			postgres: plan.PostgresPlan{
				ManagedPostgres: &plan.ManagedPostgresPlan{},
			},
			expected: true,
		},
		{
			name: "postgres plan step",
			postgres: plan.PostgresPlan{
				ManagedPostgres: &plan.ManagedPostgresPlan{},
			},
			planStep: "postgres",
			expected: true,
		},
		{
			name: "deploy plan step",
			postgres: plan.PostgresPlan{
				ManagedPostgres: &plan.ManagedPostgresPlan{},
			},
			planStep: "deploy",
			expected: false,
		},
		{
			name: "existing managed postgres",
			postgres: plan.PostgresPlan{
				ManagedPostgres: &plan.ManagedPostgresPlan{ClusterID: "mpg_123"},
			},
			expected: false,
		},
		{
			name: "unmanaged postgres",
			postgres: plan.PostgresPlan{
				FlyPostgres: &plan.FlyPostgresPlan{},
			},
			expected: false,
		},
		{
			name:     "no postgres",
			postgres: plan.PostgresPlan{},
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			state := &launchState{
				LaunchManifest: LaunchManifest{
					Plan: &plan.LaunchPlan{Postgres: tt.postgres},
				},
			}

			assert.Equal(t, tt.expected, state.willCreateManagedPostgresCluster(tt.planStep))
		})
	}
}

func TestManagedPostgresCreationPrompt(t *testing.T) {
	state := &launchState{
		LaunchManifest: LaunchManifest{
			Plan: &plan.LaunchPlan{
				AppName:    "my-app",
				RegionCode: "iad",
				Postgres: plan.PostgresPlan{
					ManagedPostgres: &plan.ManagedPostgresPlan{
						Plan: "basic",
					},
				},
			},
		},
	}

	assert.Equal(t,
		`This launch will create a new Managed Postgres database, "my-app-db", on the Basic plan ($38/mo) in iad. This is an additional paid resource. How would you like to proceed?`,
		state.managedPostgresCreationPrompt(),
	)
}

func TestLaunchWithoutManagedPostgresCluster(t *testing.T) {
	state := &launchState{
		LaunchManifest: LaunchManifest{
			Plan: &plan.LaunchPlan{
				Postgres: plan.PostgresPlan{
					ManagedPostgres: &plan.ManagedPostgresPlan{
						Plan: "basic",
					},
				},
			},
		},
	}

	state.launchWithoutManagedPostgresCluster()

	assert.Nil(t, state.Plan.Postgres.ManagedPostgres)
	assert.False(t, state.willCreateManagedPostgresCluster(""))
}

func TestIsComputeValid(t *testing.T) {
	tests := []struct {
		name     string
		compute  *appconfig.Compute
		expected bool
	}{
		{
			name:     "nil compute",
			compute:  nil,
			expected: false,
		},
		{
			name: "compute with nil MachineGuest",
			compute: &appconfig.Compute{
				MachineGuest: nil,
			},
			expected: false,
		},
		{
			name: "valid compute with MachineGuest",
			compute: &appconfig.Compute{
				MachineGuest: &fly.MachineGuest{
					CPUKind:  "shared",
					CPUs:     1,
					MemoryMB: 256,
				},
			},
			expected: true,
		},
		{
			name: "valid compute with empty MachineGuest",
			compute: &appconfig.Compute{
				MachineGuest: &fly.MachineGuest{},
			},
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := isComputeValid(tt.compute)
			assert.Equal(t, tt.expected, result)
		})
	}
}
