package socket

import (
	"context"
	"errors"
	"fmt"
	"testing"
	"time"

	altv1 "git.toki-labs.com/toki/alt/packages/contracts/gen/go/alt/v1"
	"git.toki-labs.com/toki/alt/packages/domain/market"
	"git.toki-labs.com/toki/alt/packages/domain/trading"
	"git.toki-labs.com/toki/alt/services/worker/internal/livetrading"
	protoSocket "git.toki-labs.com/toki/proto-socket/go"
)

type fakeLiveService struct {
	cap             trading.BrokerCapability
	capErr          error
	submitOrder     livetrading.LiveOrder
	submitErr       error
	cancelOrder     livetrading.LiveOrder
	cancelErr       error
	getOrder        livetrading.LiveOrder
	getErr          error
	policy          trading.RiskPolicy
	killSwitch      trading.KillSwitchState
	syncSnap        trading.AccountSnapshot
	syncSnapErr     error
	getSnap         trading.AccountSnapshot
	getSnapErr      error
	listAuditEvents []trading.AuditEvent
	listAuditErr    error
}

func (f *fakeLiveService) GetLiveBrokerCapabilities(ctx context.Context, accountID string) (trading.BrokerCapability, error) {
	return f.cap, f.capErr
}

func (f *fakeLiveService) SubmitLiveOrder(ctx context.Context, req livetrading.SubmitRequest) (livetrading.LiveOrder, error) {
	return f.submitOrder, f.submitErr
}

func (f *fakeLiveService) CancelLiveOrder(ctx context.Context, accountID, liveOrderID string) (livetrading.LiveOrder, error) {
	return f.cancelOrder, f.cancelErr
}

func (f *fakeLiveService) GetLiveOrder(ctx context.Context, accountID, liveOrderID string) (livetrading.LiveOrder, error) {
	return f.getOrder, f.getErr
}

func (f *fakeLiveService) GetRiskPolicy() trading.RiskPolicy {
	return f.policy
}

func (f *fakeLiveService) GetKillSwitch() trading.KillSwitchState {
	return f.killSwitch
}

func (f *fakeLiveService) SetKillSwitch(ks trading.KillSwitchState) trading.KillSwitchState {
	f.killSwitch = ks
	return ks
}

func sampleLiveCapability() trading.BrokerCapability {
	return trading.BrokerCapability{
		Broker:            trading.BrokerKIS,
		Markets:           map[market.Market]bool{market.MarketKR: true},
		Venues:            map[market.Venue]bool{market.VenueKRX: true},
		OrderTypes:        []trading.OrderType{trading.OrderTypeMarket, trading.OrderTypeLimit},
		SupportsCancel:    true,
		SupportsAccount:   true,
		SupportsAuditTags: false,
		CheckedAt:         time.Date(2026, 6, 1, 0, 0, 0, 0, time.UTC),
	}
}

func TestHandleGetLiveBrokerCapabilitiesSuccess(t *testing.T) {
	svc := &fakeLiveService{cap: sampleLiveCapability()}
	deps := Deps{Live: svc}

	resp, err := handleGetLiveBrokerCapabilities(deps, &altv1.GetLiveBrokerCapabilitiesRequest{AccountId: "test"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	cap := resp.GetBrokerCapabilities()
	if cap == nil {
		t.Fatal("expected broker capabilities in response")
	}
	if cap.GetBroker() != "kis" {
		t.Errorf("broker mismatch: %q", cap.GetBroker())
	}
	if !cap.GetSupportsCancel() {
		t.Error("expected supports_cancel to be true")
	}
}

func TestHandleGetLiveBrokerCapabilitiesUnavailable(t *testing.T) {
	deps := Deps{}

	resp, err := handleGetLiveBrokerCapabilities(deps, &altv1.GetLiveBrokerCapabilitiesRequest{AccountId: "test"})
	if err != nil {
		t.Fatalf("expected typed unavailable response, got error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorUnavailable {
		t.Errorf("expected unavailable code, got %q", resp.GetError().GetCode())
	}
}

func TestHandleGetLiveBrokerCapabilitiesEmptyAccountID(t *testing.T) {
	svc := &fakeLiveService{cap: sampleLiveCapability()}
	deps := Deps{Live: svc}

	resp, err := handleGetLiveBrokerCapabilities(deps, &altv1.GetLiveBrokerCapabilitiesRequest{AccountId: ""})
	if err != nil {
		t.Fatalf("expected typed invalid_request response, got error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request code, got %q", resp.GetError().GetCode())
	}
	if resp.GetError().GetMessage() != "invalid live trading request: account_id is required" {
		t.Errorf("unexpected error message: %q", resp.GetError().GetMessage())
	}
}

func TestHandleGetLiveBrokerCapabilitiesServiceError(t *testing.T) {
	svc := &fakeLiveService{capErr: errors.New("broker connection failed")}
	deps := Deps{Live: svc}

	resp, err := handleGetLiveBrokerCapabilities(deps, &altv1.GetLiveBrokerCapabilitiesRequest{AccountId: "test"})
	if err != nil {
		t.Fatalf("expected typed internal response, got error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInternal {
		t.Errorf("expected internal code, got %q", resp.GetError().GetCode())
	}
}

func TestLiveHandlersRegistration(t *testing.T) {
	registered := make(map[string]bool)
	for _, h := range liveHandlers(Deps{}) {
		if h.requestType == "" {
			t.Error("handler has empty request type")
		}
		if h.register == nil {
			t.Errorf("handler %q has nil register", h.requestType)
		}
		registered[h.requestType] = true
	}

	if !registered["alt.v1.GetLiveBrokerCapabilitiesRequest"] {
		t.Error("missing live capability handler registration")
	}
}

func TestLiveHandlersWithNilLiveService(t *testing.T) {
	// liveHandlers should still register even when deps.Live is nil.
	// The handler returns unavailable error at runtime.
	handlers := liveHandlers(Deps{})
	if len(handlers) == 0 {
		t.Error("expected live handlers to be registered even with nil Live service")
	}
}

func TestLiveSocketUnavailableReturnsTypedError(t *testing.T) {
	client := startBacktestWorkerTestClient(t, Deps{})

	resp, err := protoSocket.SendRequestTyped[*altv1.GetLiveBrokerCapabilitiesRequest, *altv1.GetLiveBrokerCapabilitiesResponse](
		&client.Communicator,
		&altv1.GetLiveBrokerCapabilitiesRequest{AccountId: "test"},
		500*time.Millisecond,
	)
	if err != nil {
		t.Fatalf("request should return typed error response without timeout: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorUnavailable {
		t.Errorf("expected unavailable code, got %q", resp.GetError().GetCode())
	}
}

func TestLiveSocketRoundTripWithFakeService(t *testing.T) {
	svc := &fakeLiveService{cap: sampleLiveCapability()}
	client := startBacktestWorkerTestClient(t, Deps{Live: svc})

	resp, err := protoSocket.SendRequestTyped[*altv1.GetLiveBrokerCapabilitiesRequest, *altv1.GetLiveBrokerCapabilitiesResponse](
		&client.Communicator,
		&altv1.GetLiveBrokerCapabilitiesRequest{AccountId: "test"},
		1*time.Second,
	)
	if err != nil {
		t.Fatalf("round trip failed: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	cap := resp.GetBrokerCapabilities()
	if cap == nil {
		t.Fatal("expected broker capabilities in response")
	}
	if cap.GetBroker() != "kis" {
		t.Errorf("broker mismatch: %q", cap.GetBroker())
	}
}

func TestLiveSocketEmptyAccountIDReturnsInvalidRequest(t *testing.T) {
	svc := &fakeLiveService{cap: sampleLiveCapability()}
	client := startBacktestWorkerTestClient(t, Deps{Live: svc})

	resp, err := protoSocket.SendRequestTyped[*altv1.GetLiveBrokerCapabilitiesRequest, *altv1.GetLiveBrokerCapabilitiesResponse](
		&client.Communicator,
		&altv1.GetLiveBrokerCapabilitiesRequest{AccountId: ""},
		500*time.Millisecond,
	)
	if err != nil {
		t.Fatalf("request should return typed error response without timeout: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request code, got %q", resp.GetError().GetCode())
	}
	if resp.GetBrokerCapabilities() != nil {
		t.Error("expected no broker capabilities when account_id is empty")
	}
}

func TestSessionHandlersIncludeLive(t *testing.T) {
	handlers := sessionHandlers(Deps{})
	seenLive := false
	for _, h := range handlers {
		if h.requestType == "alt.v1.GetLiveBrokerCapabilitiesRequest" {
			seenLive = true
			break
		}
	}
	if !seenLive {
		t.Error("sessionHandlers should include live capability handler")
	}
}

func TestLiveHandlersRegistrationIncludesOrderLifecycle(t *testing.T) {
	required := map[string]bool{
		"alt.v1.GetLiveBrokerCapabilitiesRequest": false,
		"alt.v1.SubmitLiveOrderRequest":           false,
		"alt.v1.CancelLiveOrderRequest":           false,
		"alt.v1.GetLiveOrderRequest":              false,
	}
	for _, h := range liveHandlers(Deps{}) {
		if _, ok := required[h.requestType]; ok {
			required[h.requestType] = true
		}
	}
	for name, seen := range required {
		if !seen {
			t.Errorf("missing live handler registration: %s", name)
		}
	}
}

func TestHandleSubmitLiveOrderConfirmationRequired(t *testing.T) {
	svc := &fakeLiveService{submitErr: livetrading.ErrConfirmationRequired}
	deps := Deps{Live: svc}

	resp, err := handleSubmitLiveOrder(deps, &altv1.SubmitLiveOrderRequest{
		AccountId:            "acct-1",
		Intent:               &altv1.LiveOrderIntent{InstrumentId: "KRX:005930", Side: "buy", Type: "market"},
		OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: false},
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request, got %q", resp.GetError().GetCode())
	}
}

func TestHandleSubmitLiveOrderUnavailable(t *testing.T) {
	deps := Deps{}

	resp, err := handleSubmitLiveOrder(deps, &altv1.SubmitLiveOrderRequest{
		AccountId:            "acct-1",
		Intent:               &altv1.LiveOrderIntent{InstrumentId: "KRX:005930", Side: "buy", Type: "market"},
		OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: true},
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorUnavailable {
		t.Errorf("expected unavailable, got %q", resp.GetError().GetCode())
	}
}

func TestHandleSubmitLiveOrderSuccess(t *testing.T) {
	svc := &fakeLiveService{
		submitOrder: livetrading.LiveOrder{
			ID:            "lo-acct-1-1",
			AccountID:     "acct-1",
			Status:        "submitted",
			BrokerStatus:  "ACCEPTED",
			BrokerOrderID: "broker-001",
			Intent: trading.OrderIntent{
				InstrumentID: "KRX:005930",
				Type:         "kis_best_limit",
			},
		},
	}
	deps := Deps{Live: svc}

	resp, err := handleSubmitLiveOrder(deps, &altv1.SubmitLiveOrderRequest{
		AccountId:            "acct-1",
		Intent:               &altv1.LiveOrderIntent{InstrumentId: "KRX:005930", Side: "buy", Type: "kis_best_limit"},
		OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: true, OperatorId: "op-1"},
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	if resp.GetOrder().GetId() != "lo-acct-1-1" {
		t.Errorf("unexpected order id: %q", resp.GetOrder().GetId())
	}
	if resp.GetOrder().GetType() != "kis_best_limit" {
		t.Errorf("order type not preserved: %q", resp.GetOrder().GetType())
	}
}

func TestHandleCancelLiveOrderNotFound(t *testing.T) {
	svc := &fakeLiveService{cancelErr: livetrading.ErrOrderNotFound}
	deps := Deps{Live: svc}

	resp, err := handleCancelLiveOrder(deps, &altv1.CancelLiveOrderRequest{
		AccountId:   "acct-1",
		LiveOrderId: "nonexistent",
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorNotFound {
		t.Errorf("expected not_found, got %q", resp.GetError().GetCode())
	}
}

func TestHandleGetLiveOrderSuccess(t *testing.T) {
	svc := &fakeLiveService{
		getOrder: livetrading.LiveOrder{
			ID:           "lo-acct-1-1",
			AccountID:    "acct-1",
			Status:       "filled",
			BrokerStatus: "FILLED",
		},
	}
	deps := Deps{Live: svc}

	resp, err := handleGetLiveOrder(deps, &altv1.GetLiveOrderRequest{
		AccountId:   "acct-1",
		LiveOrderId: "lo-acct-1-1",
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	if resp.GetOrder().GetStatus() != "filled" {
		t.Errorf("expected status filled, got %q", resp.GetOrder().GetStatus())
	}
	if resp.GetOrder().GetBrokerStatus() != "FILLED" {
		t.Errorf("expected broker_status FILLED, got %q", resp.GetOrder().GetBrokerStatus())
	}
}

func TestHandleSubmitLiveOrderRiskBlockedReturnsInvalidRequest(t *testing.T) {
	svc := &fakeLiveService{submitErr: livetrading.ErrRiskBlocked}
	deps := Deps{Live: svc}

	resp, err := handleSubmitLiveOrder(deps, &altv1.SubmitLiveOrderRequest{
		AccountId:            "acct-1",
		Intent:               &altv1.LiveOrderIntent{InstrumentId: "KRX:005930", Side: "buy", Type: "market"},
		OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: true},
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request for risk-blocked, got %q", resp.GetError().GetCode())
	}
}

func TestHandleSubmitLiveOrderLimitPriceCurrencyRoundTrip(t *testing.T) {
	svc := &fakeLiveService{
		submitOrder: livetrading.LiveOrder{
			ID:            "lo-acct-1-1",
			AccountID:     "acct-1",
			Status:        "submitted",
			BrokerStatus:  "ACCEPTED",
			BrokerOrderID: "broker-001",
			Intent: trading.OrderIntent{
				InstrumentID: "KRX:005930",
				Type:         "limit",
				LimitPrice:   market.Price{Currency: market.CurrencyKRW, Amount: market.Decimal{Value: "75000"}},
			},
		},
	}
	deps := Deps{Live: svc}

	resp, err := handleSubmitLiveOrder(deps, &altv1.SubmitLiveOrderRequest{
		AccountId: "acct-1",
		Intent: &altv1.LiveOrderIntent{
			InstrumentId: "KRX:005930",
			Side:         "buy",
			Type:         "limit",
			LimitPrice:   &altv1.Price{Currency: altv1.Currency_CURRENCY_KRW, Amount: &altv1.Decimal{Value: "75000"}},
		},
		OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: true, OperatorId: "op-1"},
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	lp := resp.GetOrder().GetLimitPrice()
	if lp == nil {
		t.Fatal("expected limit_price in response")
	}
	if lp.GetCurrency() != altv1.Currency_CURRENCY_KRW {
		t.Errorf("expected CURRENCY_KRW in response, got %q", lp.GetCurrency())
	}
	if lp.GetAmount().GetValue() != "75000" {
		t.Errorf("expected limit_price amount 75000, got %q", lp.GetAmount().GetValue())
	}
}

func TestHandleSubmitLiveOrderRiskBlockedIncludesOrderAndDecision(t *testing.T) {
	rejOrder := livetrading.LiveOrder{
		ID:              "lo-acct-1-1",
		AccountID:       "acct-1",
		Status:          trading.OrderStatusRejected,
		RejectionReason: "kill switch is active",
	}
	svc := &fakeLiveService{
		submitOrder: rejOrder,
		submitErr:   fmt.Errorf("%w: kill switch is active", livetrading.ErrRiskBlocked),
	}
	deps := Deps{Live: svc}

	resp, err := handleSubmitLiveOrder(deps, &altv1.SubmitLiveOrderRequest{
		AccountId:            "acct-1",
		Intent:               &altv1.LiveOrderIntent{InstrumentId: "KRX:005930", Side: "buy", Type: "market"},
		OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: true},
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error for risk-blocked, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request, got %q", resp.GetError().GetCode())
	}
	if resp.GetOrder() == nil {
		t.Fatal("expected rejected order in response, got nil")
	}
	if resp.GetOrder().GetId() != "lo-acct-1-1" {
		t.Errorf("unexpected order id: %q", resp.GetOrder().GetId())
	}
	if resp.GetRiskDecision() == nil {
		t.Fatal("expected risk decision in response, got nil")
	}
	if resp.GetRiskDecision().GetAllowed() {
		t.Error("expected risk decision allowed=false")
	}
	if resp.GetRiskDecision().GetReason() != "kill switch is active" {
		t.Errorf("unexpected risk decision reason: %q", resp.GetRiskDecision().GetReason())
	}
}

func TestHandleSubmitLiveOrderInvalidCurrencyReturnsInvalidRequest(t *testing.T) {
	svc := &fakeLiveService{}
	deps := Deps{Live: svc}

	resp, err := handleSubmitLiveOrder(deps, &altv1.SubmitLiveOrderRequest{
		AccountId: "acct-1",
		Intent: &altv1.LiveOrderIntent{
			InstrumentId: "KRX:005930",
			Side:         "buy",
			Type:         "limit",
			LimitPrice:   &altv1.Price{Currency: altv1.Currency_CURRENCY_UNSPECIFIED, Amount: &altv1.Decimal{Value: "75000"}},
		},
		OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: true, OperatorId: "op-1"},
	})
	if err != nil {
		t.Fatalf("unexpected go error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error for unsupported currency, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request, got %q", resp.GetError().GetCode())
	}
}

func TestSubmitLiveOrderSocketRoundTrip(t *testing.T) {
	svc := &fakeLiveService{
		submitOrder: livetrading.LiveOrder{
			ID:            "lo-acct-1-1",
			AccountID:     "acct-1",
			Status:        "submitted",
			BrokerStatus:  "ACCEPTED",
			BrokerOrderID: "broker-001",
			Intent:        trading.OrderIntent{InstrumentID: "KRX:005930", Type: "market"},
		},
	}
	client := startBacktestWorkerTestClient(t, Deps{Live: svc})

	resp, err := protoSocket.SendRequestTyped[*altv1.SubmitLiveOrderRequest, *altv1.SubmitLiveOrderResponse](
		&client.Communicator,
		&altv1.SubmitLiveOrderRequest{
			AccountId:            "acct-1",
			Intent:               &altv1.LiveOrderIntent{InstrumentId: "KRX:005930", Side: "buy", Type: "market"},
			OperatorConfirmation: &altv1.OperatorConfirmation{Confirmed: true, OperatorId: "op-1"},
		},
		1*time.Second,
	)
	if err != nil {
		t.Fatalf("round trip failed: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	if resp.GetOrder().GetId() != "lo-acct-1-1" {
		t.Errorf("unexpected order id: %q", resp.GetOrder().GetId())
	}
}

func (f *fakeLiveService) SyncLiveAccount(ctx context.Context, accountID string) (trading.AccountSnapshot, error) {
	return f.syncSnap, f.syncSnapErr
}

func (f *fakeLiveService) GetLiveAccountSnapshot(ctx context.Context, accountID string) (trading.AccountSnapshot, error) {
	return f.getSnap, f.getSnapErr
}

func (f *fakeLiveService) ListLiveAuditEvents(_ context.Context, _ trading.AuditFilter) ([]trading.AuditEvent, error) {
	return f.listAuditEvents, f.listAuditErr
}

func sampleAccountSnapshotForSocket() trading.AccountSnapshot {
	return trading.AccountSnapshot{
		Broker:    trading.BrokerKIS,
		AccountID: "op-alias-001",
		Cash: []trading.CashBalance{
			{Currency: market.CurrencyKRW, Amount: market.Decimal{Value: "5000000"}},
		},
		Positions: []trading.PositionSnapshot{
			{
				InstrumentID: "KRX:005930",
				Side:         trading.OrderSideBuy,
				Quantity:     market.Quantity{Amount: market.Decimal{Value: "10"}},
			},
		},
		Stale: false,
	}
}

func TestHandleSyncLiveAccountSuccess(t *testing.T) {
	snap := sampleAccountSnapshotForSocket()
	svc := &fakeLiveService{syncSnap: snap}
	deps := Deps{Live: svc}

	resp, err := handleSyncLiveAccount(deps, &altv1.SyncLiveAccountRequest{AccountId: "op-alias-001"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	s := resp.GetSnapshot()
	if s == nil {
		t.Fatal("expected snapshot in response")
	}
	if s.GetAccountId() != "op-alias-001" {
		t.Errorf("account_id mismatch: %q", s.GetAccountId())
	}
	if s.GetBroker() != "kis" {
		t.Errorf("broker mismatch: %q", s.GetBroker())
	}
	if len(s.GetCash()) != 1 {
		t.Errorf("expected 1 cash entry, got %d", len(s.GetCash()))
	}
	if s.GetStale() {
		t.Error("expected stale=false")
	}
}

func TestHandleSyncLiveAccountEmptyAccountIDReturnsInvalidRequest(t *testing.T) {
	svc := &fakeLiveService{}
	deps := Deps{Live: svc}

	resp, err := handleSyncLiveAccount(deps, &altv1.SyncLiveAccountRequest{AccountId: ""})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request, got %q", resp.GetError().GetCode())
	}
}

func TestHandleSyncLiveAccountNilServiceReturnsUnavailable(t *testing.T) {
	resp, err := handleSyncLiveAccount(Deps{}, &altv1.SyncLiveAccountRequest{AccountId: "op-alias-001"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorUnavailable {
		t.Errorf("expected unavailable, got %q", resp.GetError().GetCode())
	}
}

func TestHandleGetLiveAccountSnapshotNotFound(t *testing.T) {
	svc := &fakeLiveService{getSnapErr: livetrading.ErrAccountSnapshotNotFound}
	deps := Deps{Live: svc}

	resp, err := handleGetLiveAccountSnapshot(deps, &altv1.GetLiveAccountSnapshotRequest{AccountId: "op-alias-001"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorNotFound {
		t.Errorf("expected not_found, got %q", resp.GetError().GetCode())
	}
}

func TestHandleGetLiveAccountSnapshotSuccess(t *testing.T) {
	snap := sampleAccountSnapshotForSocket()
	svc := &fakeLiveService{getSnap: snap}
	deps := Deps{Live: svc}

	resp, err := handleGetLiveAccountSnapshot(deps, &altv1.GetLiveAccountSnapshotRequest{AccountId: "op-alias-001"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	if resp.GetSnapshot() == nil {
		t.Fatal("expected snapshot in response")
	}
	if resp.GetSnapshot().GetAccountId() != "op-alias-001" {
		t.Errorf("account_id mismatch: %q", resp.GetSnapshot().GetAccountId())
	}
}

func TestLiveHandlersRegistrationIncludesAccountSync(t *testing.T) {
	required := map[string]bool{
		"alt.v1.SyncLiveAccountRequest":        false,
		"alt.v1.GetLiveAccountSnapshotRequest": false,
	}
	for _, h := range liveHandlers(Deps{}) {
		if _, ok := required[h.requestType]; ok {
			required[h.requestType] = true
		}
	}
	for name, seen := range required {
		if !seen {
			t.Errorf("missing live handler registration: %s", name)
		}
	}
}

func TestLiveHandlersRegistrationIncludesAuditQuery(t *testing.T) {
	found := false
	for _, h := range liveHandlers(Deps{}) {
		if h.requestType == "alt.v1.ListLiveAuditEventsRequest" {
			found = true
			break
		}
	}
	if !found {
		t.Error("missing live handler registration: alt.v1.ListLiveAuditEventsRequest")
	}
}

func TestHandleListLiveAuditEventsSuccess(t *testing.T) {
	events := []trading.AuditEvent{
		{
			EventID:   "aud-1",
			Type:      trading.AuditEventTypeSubmitConfirmed,
			Timestamp: time.Now().UTC(),
			AccountID: "acct-1",
			OrderID:   "lo-acct-1-1",
			Status:    "submitted",
			Actor:     "op-001",
		},
		{
			EventID:   "aud-2",
			Type:      trading.AuditEventTypeRiskBlocked,
			Timestamp: time.Now().UTC(),
			AccountID: "acct-1",
			Status:    "blocked",
		},
	}
	svc := &fakeLiveService{listAuditEvents: events}
	deps := Deps{Live: svc}

	resp, err := handleListLiveAuditEvents(deps, &altv1.ListLiveAuditEventsRequest{AccountId: "acct-1"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	if len(resp.GetEvents()) != 2 {
		t.Fatalf("expected 2 events, got %d", len(resp.GetEvents()))
	}
	if resp.GetEvents()[0].GetEventId() != "aud-1" {
		t.Errorf("event_id mismatch: %q", resp.GetEvents()[0].GetEventId())
	}
	if resp.GetEvents()[0].GetType() != string(trading.AuditEventTypeSubmitConfirmed) {
		t.Errorf("type mismatch: %q", resp.GetEvents()[0].GetType())
	}
	if resp.GetEvents()[0].GetActor() != "op-001" {
		t.Errorf("actor mismatch: %q", resp.GetEvents()[0].GetActor())
	}
}

func TestHandleListLiveAuditEventsEmptyAccountIDReturnsInvalidRequest(t *testing.T) {
	svc := &fakeLiveService{}
	deps := Deps{Live: svc}

	resp, err := handleListLiveAuditEvents(deps, &altv1.ListLiveAuditEventsRequest{AccountId: ""})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInvalidRequest {
		t.Errorf("expected invalid_request, got %q", resp.GetError().GetCode())
	}
}

func TestHandleListLiveAuditEventsNilServiceReturnsUnavailable(t *testing.T) {
	resp, err := handleListLiveAuditEvents(Deps{}, &altv1.ListLiveAuditEventsRequest{AccountId: "acct-1"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorUnavailable {
		t.Errorf("expected unavailable, got %q", resp.GetError().GetCode())
	}
}

func TestHandleListLiveAuditEventsServiceErrorReturnsInternal(t *testing.T) {
	svc := &fakeLiveService{listAuditErr: errors.New("store unavailable")}
	deps := Deps{Live: svc}

	resp, err := handleListLiveAuditEvents(deps, &altv1.ListLiveAuditEventsRequest{AccountId: "acct-1"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() == nil {
		t.Fatal("expected typed error, got nil")
	}
	if resp.GetError().GetCode() != backtestErrorInternal {
		t.Errorf("expected internal, got %q", resp.GetError().GetCode())
	}
}

func TestHandleListLiveAuditEventsEmptyResultIsOK(t *testing.T) {
	svc := &fakeLiveService{listAuditEvents: nil}
	deps := Deps{Live: svc}

	resp, err := handleListLiveAuditEvents(deps, &altv1.ListLiveAuditEventsRequest{AccountId: "acct-1"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.GetError() != nil {
		t.Fatalf("unexpected typed error: %+v", resp.GetError())
	}
	if len(resp.GetEvents()) != 0 {
		t.Errorf("expected empty events, got %d", len(resp.GetEvents()))
	}
}
