package cmd

import (
	"context"
	"errors"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	cpaws "github.com/tidbcloud/controlplane9/internal/aws"
	"github.com/tidbcloud/controlplane9/internal/byoc"
	"github.com/tidbcloud/controlplane9/internal/cluster"
	"github.com/tidbcloud/controlplane9/internal/config"
	"github.com/tidbcloud/controlplane9/internal/host"
)

func TestDestroyRemoteRuntimeHostGoneForContextHandlesEmptyInstanceByHostReadyState(t *testing.T) {
	original := destroyObserveRemoteRuntimeHostGone
	observerCalls := 0
	destroyObserveRemoteRuntimeHostGone = func(context.Context, byoc.Input) (bool, error) {
		observerCalls++
		return false, errors.New("provider observer reached")
	}
	t.Cleanup(func() { destroyObserveRemoteRuntimeHostGone = original })

	state := cluster.NewStateForLifecycle("session", "session", cluster.LifecycleV3)
	state.HostMode = config.HostModeRemoteEC2K3d
	state.MarkRunning(cluster.StepHostReady)
	state.MarkFailed(cluster.StepHostReady, errors.New("InvalidKeyPair.NotFound"))
	destroyCtx := &v1alpha2DestroyContext{
		State: state,
		Selected: &host.Session{
			Mode:   config.HostModeRemoteEC2K3d,
			Remote: &host.RemoteSession{},
		},
		AWSState: &cpaws.SessionState{Region: "us-west-2", Account: "123456789012"},
	}

	gone, err := destroyRemoteRuntimeHostGoneForContext(context.Background(), destroyCtx)
	if err != nil || !gone || observerCalls != 0 {
		t.Fatalf("failed host_ready: gone=%v observer_calls=%d err=%v", gone, observerCalls, err)
	}

	state.MarkDone(cluster.StepHostReady)
	gone, err = destroyRemoteRuntimeHostGoneForContext(context.Background(), destroyCtx)
	if gone || err == nil || !strings.Contains(err.Error(), "missing instance ID") || observerCalls != 0 {
		t.Fatalf("done host_ready: gone=%v observer_calls=%d err=%v", gone, observerCalls, err)
	}
}

func TestDestroyCloudCleanupWorkflowObservationUsesRepositoryRunsEndpoint(t *testing.T) {
	const (
		runID         = int64(29709999752)
		dispatchID    = "230f53e06cf07461c1179d7c399ecb5a"
		expectedTitle = "cp9 cleanup owner=owner session=session region=us-west-2 dispatch=" + dispatchID
	)
	dir := t.TempDir()
	script := `#!/bin/sh
if [ "$1" != "api" ]; then
  exit 91
fi
if [ "$GH_COLOR" != "never" ]; then
  echo "gh child env missing GH_COLOR=never" >&2
  exit 92
fi
if [ -n "${FORCE_COLOR+x}" ]; then
  echo "gh child env still has FORCE_COLOR" >&2
  exit 93
fi
printf '%s\n' '{"workflow_runs":[{"id":1,"html_url":"https://example.invalid/1","status":"queued","event":"workflow_dispatch","display_title":"` + expectedTitle + `","head_branch":"main","path":".github/workflows/other.yml"},{"id":29709999752,"html_url":"https://github.com/tidbcloud/controlplane9/actions/runs/29709999752","status":"queued","conclusion":null,"event":"workflow_dispatch","display_title":"` + expectedTitle + `","head_branch":"main","path":".github/workflows/cp9-session-cleanup.yml"}]}'
`
	ghPath := filepath.Join(dir, "gh")
	if err := os.WriteFile(ghPath, []byte(script), 0o600); err != nil {
		t.Fatal(err)
	}
	if err := os.Chmod(ghPath, 0o700); err != nil {
		t.Fatal(err)
	}
	t.Setenv("PATH", dir)
	t.Setenv("FORCE_COLOR", "1")

	receipt := &destroyCloudCleanupHandoffReceipt{
		Repo:       "tidbcloud/controlplane9",
		Ref:        "main",
		Workflow:   "cp9-session-cleanup.yml",
		DispatchID: dispatchID,
		PreparedAt: time.Now().Add(-time.Minute),
	}
	run, err := observeDestroyCloudCleanupWorkflowRun(
		context.Background(),
		receipt,
		cpaws.Scope{Owner: "owner", SessionID: "session"},
		"us-west-2",
	)
	if err != nil {
		t.Fatal(err)
	}
	if run.DatabaseID != runID {
		t.Fatalf("observed run %d, want %d", run.DatabaseID, runID)
	}

	lookedUp, err := lookupDestroyCloudCleanupWorkflowRun(context.Background(), receipt.Repo, runID)
	if err != nil {
		t.Fatal(err)
	}
	if lookedUp.DatabaseID != runID {
		t.Fatalf("looked up run %d, want %d", lookedUp.DatabaseID, runID)
	}
}
