package payment

import (
	"context"
	"encoding/json"
	"testing"

	"kra/internal/modules/system/biz"
)

func TestMigrateSeedsPaymentProviders(t *testing.T) {
	db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared")
	if err != nil {
		t.Fatal(err)
	}
	if err = migrateAll(db); err != nil {
		t.Fatal(err)
	}
	var count int64
	if err = db.Model(&integrationConfigPO{}).Where("kind = ?", integrationKindPayment).Count(&count).Error; err != nil {
		t.Fatal(err)
	}
	if count != int64(len(biz.SupportedPaymentProviders)) {
		t.Fatalf("payment providers = %d", count)
	}
	if !db.Migrator().HasTable("pay_orders") {
		t.Fatal("payment migration must create pay_orders")
	}
	if db.Migrator().HasTable("pay_callback_events") {
		t.Fatal("payment migration must not create pay_callback_events")
	}
}

func TestPaymentSecretMaskAndMerge(t *testing.T) {
	values := map[string]any{"app_id": "a", "private_key": "private", "nested": map[string]any{"api_v3_key": "key"}}
	maskPaymentSecrets(values)
	if values["private_key"] != "******" || values["nested"].(map[string]any)["api_v3_key"] != "******" {
		t.Fatalf("not masked: %#v", values)
	}
	mergePaymentSecrets(values, map[string]any{"private_key": "private", "nested": map[string]any{"api_v3_key": "key"}})
	if values["private_key"] != "private" || values["nested"].(map[string]any)["api_v3_key"] != "key" {
		t.Fatalf("not merged: %#v", values)
	}
}

func TestPaymentConfigListMasksAndSavePreservesSecretAliases(t *testing.T) {
	db := openIntegrationConfigTestDB(t)
	repo := &paymentRepo{data: &Data{gormDB: newReloadableDB(db, nil)}}
	secrets := map[string]string{
		"app_key":        "app-key-secret",
		"token":          "signing-token",
		"key_content":    "private-key-content",
		"pkcs12_content": "pkcs12-content",
		"op_user_passwd": "operator-password",
		"api_v3key":      "api-v3-key-alias",
		"apiv3_key":      "api-v3-key-compact-alias",
		"key_pem":        "key-pem-content",
		"apiclient_key":  "api-client-key-content",
	}
	storedValues := map[string]any{"app_id": "public-app-id"}
	for key, value := range secrets {
		storedValues[key] = value
	}
	storedValues["nested"] = map[string]any{"token": "nested-token"}
	raw, err := json.Marshal(storedValues)
	if err != nil {
		t.Fatal(err)
	}
	if err = db.Create(&integrationConfigPO{
		Kind: integrationKindPayment, Provider: biz.PaymentQQ, Config: string(raw),
	}).Error; err != nil {
		t.Fatal(err)
	}

	configs, err := repo.ListConfigs(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	if len(configs) != 1 {
		t.Fatalf("payment configs = %d, want 1", len(configs))
	}
	masked := map[string]any{}
	if err = json.Unmarshal(configs[0].Values, &masked); err != nil {
		t.Fatal(err)
	}
	if masked["app_id"] != "public-app-id" {
		t.Fatalf("non-secret app_id = %#v, want public-app-id", masked["app_id"])
	}
	for key := range secrets {
		if masked[key] != "******" {
			t.Errorf("secret %s = %#v, want masked value", key, masked[key])
		}
	}
	if nested, ok := masked["nested"].(map[string]any); !ok || nested["token"] != "******" {
		t.Errorf("nested token was not masked: %#v", masked["nested"])
	}

	if err = repo.SaveConfig(context.Background(), &biz.PaymentConfig{
		Provider: biz.PaymentQQ, Values: configs[0].Values,
	}); err != nil {
		t.Fatal(err)
	}
	var row integrationConfigPO
	if err = db.Where("kind = ? AND provider = ?", integrationKindPayment, biz.PaymentQQ).First(&row).Error; err != nil {
		t.Fatal(err)
	}
	preserved := map[string]any{}
	if err = json.Unmarshal([]byte(row.Config), &preserved); err != nil {
		t.Fatal(err)
	}
	for key, want := range secrets {
		if preserved[key] != want {
			t.Errorf("preserved secret %s = %#v, want %q", key, preserved[key], want)
		}
	}
	if nested, ok := preserved["nested"].(map[string]any); !ok || nested["token"] != "nested-token" {
		t.Errorf("nested token was not preserved: %#v", preserved["nested"])
	}
}
