package service

import (
	"context"
	"testing"
	"time"

	"oci-portal/internal/oci"
)

// consoleFakeClient 在 fakeClient 上覆写控制台连接三方法：
// 首次 List 返回预置连接，删除后的后续 List 全部报告 DELETED。
type consoleFakeClient struct {
	fakeClient

	conns   []oci.ConsoleConnection
	listed  int
	deleted []string
	created int
}

func (f *consoleFakeClient) ListConsoleConnections(ctx context.Context, cred oci.Credentials, region, instanceID string) ([]oci.ConsoleConnection, error) {
	f.listed++
	if f.listed == 1 {
		return f.conns, nil
	}
	gone := make([]oci.ConsoleConnection, len(f.conns))
	for i, c := range f.conns {
		c.LifecycleState = "DELETED"
		gone[i] = c
	}
	return gone, nil
}

func (f *consoleFakeClient) DeleteConsoleConnection(ctx context.Context, cred oci.Credentials, region, connectionID string) error {
	f.deleted = append(f.deleted, connectionID)
	return nil
}

func (f *consoleFakeClient) CreateConsoleConnection(ctx context.Context, cred oci.Credentials, region, instanceID, sshPublicKey string) (oci.ConsoleConnection, error) {
	f.created++
	return oci.ConsoleConnection{
		ID:             "ocid1.icc.new",
		InstanceID:     instanceID,
		LifecycleState: "ACTIVE",
		VncConnectionString: "ssh -o ProxyCommand='ssh -W %h:%p -p 443 " +
			"ocid1.icc.new@instance-console.eu-frankfurt-1.oci.oraclecloud.com' -N -L ...",
	}, nil
}

func newConsoleTestService(t *testing.T, client *consoleFakeClient) (*ConsoleService, uint) {
	t.Helper()
	client.tenancy = oci.TenancyInfo{Name: "t"}
	svc := newTestService(t, client)
	cfg, err := svc.Import(context.Background(), trialImportInput())
	if err != nil {
		t.Fatalf("import config: %v", err)
	}
	console := NewConsoleService(svc)
	console.pollInterval = time.Millisecond
	return console, cfg.ID
}

func TestCreateConsoleSession(t *testing.T) {
	tests := []struct {
		name        string
		typ         string
		conns       []oci.ConsoleConnection
		wantErr     bool
		wantDeleted int
	}{
		{name: "非法类型拒绝", typ: "rdp", wantErr: true},
		{name: "无残留直接创建", typ: ConsoleTypeSerial},
		{
			name: "ACTIVE 残留先删再建",
			typ:  ConsoleTypeVnc,
			conns: []oci.ConsoleConnection{
				{ID: "ocid1.icc.stale", LifecycleState: "ACTIVE"},
			},
			wantDeleted: 1,
		},
		{
			name: "DELETED 终态记录跳过",
			typ:  ConsoleTypeSerial,
			conns: []oci.ConsoleConnection{
				{ID: "ocid1.icc.gone", LifecycleState: "DELETED"},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			client := &consoleFakeClient{conns: tt.conns}
			console, cfgID := newConsoleTestService(t, client)
			sess, err := console.CreateSession(context.Background(), cfgID, "ocid1.instance.i", "", tt.typ)
			if tt.wantErr {
				if err == nil {
					t.Fatal("expect error, got nil")
				}
				return
			}
			if err != nil {
				t.Fatalf("CreateSession: %v", err)
			}
			if sess.Type != tt.typ {
				t.Errorf("session type = %s, want %s", sess.Type, tt.typ)
			}
			if len(client.deleted) != tt.wantDeleted {
				t.Errorf("deleted %d stale connections, want %d", len(client.deleted), tt.wantDeleted)
			}
			if client.created != 1 {
				t.Errorf("created %d connections, want 1", client.created)
			}
			if console.Get(sess.ID) == nil {
				t.Error("session not retrievable after create")
			}
		})
	}
}
