package authentication

import (
	"strings"
	"testing"

	"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
)

func TestGB32960PlatformAuthenticatorModes(t *testing.T) {
	env := envelope.FrameEnvelope{
		Protocol:  envelope.ProtocolGB32960,
		MessageID: "0x05",
		Parsed: map[string]any{
			"platform_login": map[string]any{"username": "platform-a", "password": "secret-a"},
		},
	}

	accepted := NewGB32960PlatformAuthenticator(ModeEnforce, map[string][]string{"platform-a": {"secret-a"}}).Authenticate(env)
	if !accepted.Applicable || !accepted.Allowed || accepted.Status != StatusAccepted {
		t.Fatalf("accepted result = %#v", accepted)
	}

	rejected := NewGB32960PlatformAuthenticator(ModeEnforce, map[string][]string{"platform-a": {"other"}}).Authenticate(env)
	if !rejected.Applicable || rejected.Allowed || rejected.Status != StatusRejected {
		t.Fatalf("enforced rejected result = %#v", rejected)
	}

	observed := NewGB32960PlatformAuthenticator(ModeObserve, map[string][]string{"platform-a": {"other"}}).Authenticate(env)
	if !observed.Allowed || observed.Status != StatusRejected {
		t.Fatalf("observed rejected result = %#v", observed)
	}
}

func TestGB32960PlatformAuthenticatorReportsUnknownAccount(t *testing.T) {
	env := envelope.FrameEnvelope{
		Protocol:  envelope.ProtocolGB32960,
		MessageID: "0x05",
		Parsed: map[string]any{
			"platform_login": map[string]any{"username": "unknown", "password": "secret"},
		},
	}
	result := NewGB32960PlatformAuthenticator(ModeEnforce, map[string][]string{"known": {"secret"}}).Authenticate(env)
	if result.Allowed || result.Status != StatusUnknownAccount {
		t.Fatalf("result = %#v", result)
	}
}

func TestJT808AuthenticatorValidatesAuthenticationFrame(t *testing.T) {
	env := envelope.FrameEnvelope{
		Protocol:  envelope.ProtocolJT808,
		MessageID: "0x0102",
		Parsed: map[string]any{
			"authentication": map[string]any{"token": "issued-code"},
		},
	}
	accepted := NewJT808Authenticator(ModeEnforce, "issued-code", nil).Authenticate(env)
	if !accepted.Allowed || accepted.Status != StatusAccepted {
		t.Fatalf("accepted result = %#v", accepted)
	}
	rejected := NewJT808Authenticator(ModeEnforce, "different-code", nil).Authenticate(env)
	if rejected.Allowed || rejected.Status != StatusRejected {
		t.Fatalf("rejected result = %#v", rejected)
	}
}

func TestJT808AuthenticatorAcceptsDeviceSnapshotToken(t *testing.T) {
	env := envelope.FrameEnvelope{
		Protocol:  envelope.ProtocolJT808,
		MessageID: "0x0102",
		Phone:     "013307795425",
		Parsed: map[string]any{
			"authentication": map[string]any{"token": "device-code"},
		},
	}
	provider := staticJT808DeviceTokens{"13307795425": "device-code"}
	result := NewJT808Authenticator(ModeEnforce, "configured-code", provider).Authenticate(env)
	if !result.Allowed || result.Status != StatusAccepted || result.Source != "device" {
		t.Fatalf("device token result = %#v", result)
	}
}

type staticJT808DeviceTokens map[string]string

func (p staticJT808DeviceTokens) JT808AuthToken(phone string) (string, bool) {
	phone = strings.TrimLeft(phone, "0")
	token, ok := p[phone]
	return token, ok
}

func TestRedactParsedCredentialsRemovesGB32960Password(t *testing.T) {
	login := map[string]any{"username": "platform-a", "password": "secret-a"}
	env := envelope.FrameEnvelope{
		Protocol: envelope.ProtocolGB32960,
		Parsed:   map[string]any{"platform_login": login},
	}

	RedactParsedCredentials(&env)
	if _, exists := login["password"]; exists {
		t.Fatalf("password remained in parsed login: %#v", login)
	}
	if login["password_present"] != true {
		t.Fatalf("password presence marker missing: %#v", login)
	}
}

func TestParseModeRejectsUnknownValue(t *testing.T) {
	if _, err := ParseMode("strict-ish", ModeObserve); err == nil {
		t.Fatal("expected unsupported mode error")
	}
}
