package oci

import (
	"context"
	"fmt"
	"time"

	"github.com/oracle/oci-go-sdk/v65/core"
)

// ConsoleConnection 是实例控制台连接。VNC 连接串在本地建立 SSH 隧道后，
// 用 VNC 客户端连 localhost:5900 即可（串口控制台直接执行 ConnectionString）。
type ConsoleConnection struct {
	ID                  string `json:"id"`
	InstanceID          string `json:"instanceId"`
	LifecycleState      string `json:"lifecycleState"`
	ConnectionString    string `json:"connectionString"`    // 串口控制台 SSH 命令
	VncConnectionString string `json:"vncConnectionString"` // VNC over SSH 隧道命令
}

// CreateConsoleConnection 实现 Client：为实例创建控制台连接并等待就绪，
// 返回包含 VNC/串口连接串的对象；等待超时返回当前状态（可稍后再查列表）。
func (c *RealClient) CreateConsoleConnection(ctx context.Context, cred Credentials, region, instanceID, sshPublicKey string) (ConsoleConnection, error) {
	cc, err := c.computeClient(cred, region)
	if err != nil {
		return ConsoleConnection{}, err
	}
	resp, err := cc.CreateInstanceConsoleConnection(ctx, core.CreateInstanceConsoleConnectionRequest{
		CreateInstanceConsoleConnectionDetails: core.CreateInstanceConsoleConnectionDetails{
			InstanceId: &instanceID,
			PublicKey:  &sshPublicKey,
		},
	})
	if err != nil {
		return ConsoleConnection{}, fmt.Errorf("create console connection: %w", err)
	}
	return c.waitConsoleConnectionActive(ctx, cc, deref(resp.Id))
}

// waitConsoleConnectionActive 轮询等待控制台连接 ACTIVE，最长约 60 秒。
func (c *RealClient) waitConsoleConnectionActive(ctx context.Context, cc core.ComputeClient, connectionID string) (ConsoleConnection, error) {
	var last ConsoleConnection
	for i := 0; i < 30; i++ {
		resp, err := cc.GetInstanceConsoleConnection(ctx, core.GetInstanceConsoleConnectionRequest{
			InstanceConsoleConnectionId: &connectionID,
		})
		if err != nil {
			return last, fmt.Errorf("poll console connection: %w", err)
		}
		last = toConsoleConnection(resp.InstanceConsoleConnection)
		if last.LifecycleState == string(core.InstanceConsoleConnectionLifecycleStateActive) {
			return last, nil
		}
		select {
		case <-ctx.Done():
			return last, fmt.Errorf("poll console connection: %w", ctx.Err())
		case <-time.After(2 * time.Second):
		}
	}
	return last, nil
}

// ListConsoleConnections 实现 Client：列出实例的控制台连接。
func (c *RealClient) ListConsoleConnections(ctx context.Context, cred Credentials, region, instanceID string) ([]ConsoleConnection, error) {
	cc, err := c.computeClient(cred, region)
	if err != nil {
		return nil, err
	}
	// 控制台连接记录在实例所在 compartment，先取实例定位，传租户根会漏查
	instResp, err := cc.GetInstance(ctx, core.GetInstanceRequest{InstanceId: &instanceID})
	if err != nil {
		return nil, fmt.Errorf("get instance %s: %w", instanceID, err)
	}
	resp, err := cc.ListInstanceConsoleConnections(ctx, core.ListInstanceConsoleConnectionsRequest{
		CompartmentId: hostCompartment(cred, deref(instResp.CompartmentId)),
		InstanceId:    &instanceID,
	})
	if err != nil {
		return nil, fmt.Errorf("list console connections: %w", err)
	}
	connections := make([]ConsoleConnection, 0, len(resp.Items))
	for _, item := range resp.Items {
		connections = append(connections, toConsoleConnection(item))
	}
	return connections, nil
}

// DeleteConsoleConnection 实现 Client：删除控制台连接。
func (c *RealClient) DeleteConsoleConnection(ctx context.Context, cred Credentials, region, connectionID string) error {
	cc, err := c.computeClient(cred, region)
	if err != nil {
		return err
	}
	_, err = cc.DeleteInstanceConsoleConnection(ctx, core.DeleteInstanceConsoleConnectionRequest{
		InstanceConsoleConnectionId: &connectionID,
	})
	if err != nil {
		return fmt.Errorf("delete console connection %s: %w", connectionID, err)
	}
	return nil
}

func toConsoleConnection(conn core.InstanceConsoleConnection) ConsoleConnection {
	return ConsoleConnection{
		ID:                  deref(conn.Id),
		InstanceID:          deref(conn.InstanceId),
		LifecycleState:      string(conn.LifecycleState),
		ConnectionString:    deref(conn.ConnectionString),
		VncConnectionString: deref(conn.VncConnectionString),
	}
}
