package invite_test

import (
	"context"
	"testing"

	invitedomain "hyapp/services/user-service/internal/domain/invite"
	userdomain "hyapp/services/user-service/internal/domain/user"
	"hyapp/services/user-service/internal/testutil/mysqltest"
)

func TestInviteRelationCountersAndRechargeValidity(t *testing.T) {
	repo := mysqltest.NewRepository(t)
	ctx := context.Background()

	createUser(t, repo, 10001, "163001", 1000)
	createUser(t, repo, 10002, "163002", 1001)

	inviter, err := repo.GetUser(ctx, 10001)
	if err != nil {
		t.Fatalf("get inviter failed: %v", err)
	}
	if inviter.InviteOverview.MyInviteCode == "" || !inviter.InviteOverview.InviteEnabled || inviter.InviteOverview.ValidInviteThresholdCoin != 80000 {
		t.Fatalf("inviter should have active code and default policy threshold: %+v", inviter.InviteOverview)
	}

	invited, err := repo.CompleteOnboarding(ctx, userdomain.CompleteOnboardingCommand{
		AppCode:       "lalu",
		UserID:        10002,
		Username:      "alice",
		Avatar:        "https://cdn.example/a.png",
		Gender:        "female",
		Country:       "SG",
		InviteCode:    inviter.InviteOverview.MyInviteCode,
		RequestID:     "req-invite-bind",
		CompletedAtMs: 2000,
	})
	if err != nil {
		t.Fatalf("complete onboarding with invite failed: %v", err)
	}
	if !invited.InviteBinding.Bound || invited.InviteBinding.InviterUserID != 10001 {
		t.Fatalf("invite binding mismatch: %+v", invited.InviteBinding)
	}

	inviter, err = repo.GetUser(ctx, 10001)
	if err != nil {
		t.Fatalf("get inviter after bind failed: %v", err)
	}
	if inviter.InviteOverview.InviteCount != 1 || inviter.InviteOverview.ValidInviteCount != 0 {
		t.Fatalf("invite counter after bind mismatch: %+v", inviter.InviteOverview)
	}

	inviteRepo := repo.Repository.InviteRepository()
	first, err := inviteRepo.ApplyRechargeEvent(ctx, invitedomain.RechargeEvent{
		AppCode:            "lalu",
		EventID:            "evt-recharge-1",
		EventType:          invitedomain.RechargeEventWalletRecorded,
		TransactionID:      "tx-recharge-1",
		CommandID:          "cmd-recharge-1",
		InvitedUserID:      10002,
		AssetType:          "COIN",
		RechargeCoinAmount: 79999,
		RechargeType:       invitedomain.RechargeTypeCoinSellerTransfer,
		OccurredAtMs:       3000,
	})
	if err != nil || !first.Consumed || first.Valid {
		t.Fatalf("first recharge result mismatch: result=%+v err=%v", first, err)
	}
	inviter, _ = repo.GetUser(ctx, 10001)
	if inviter.InviteOverview.ValidInviteCount != 0 {
		t.Fatalf("79999 coin must not count as valid invite: %+v", inviter.InviteOverview)
	}

	second, err := inviteRepo.ApplyRechargeEvent(ctx, invitedomain.RechargeEvent{
		AppCode:            "lalu",
		EventID:            "evt-recharge-2",
		EventType:          invitedomain.RechargeEventWalletRecorded,
		TransactionID:      "tx-recharge-2",
		CommandID:          "cmd-recharge-2",
		InvitedUserID:      10002,
		AssetType:          "COIN",
		RechargeCoinAmount: 1,
		RechargeType:       invitedomain.RechargeTypeCoinSellerTransfer,
		OccurredAtMs:       4000,
	})
	if err != nil || !second.Consumed || !second.Valid {
		t.Fatalf("second recharge should make invite valid: result=%+v err=%v", second, err)
	}
	duplicate, err := inviteRepo.ApplyRechargeEvent(ctx, invitedomain.RechargeEvent{
		AppCode:            "lalu",
		EventID:            "evt-recharge-2",
		EventType:          invitedomain.RechargeEventWalletRecorded,
		TransactionID:      "tx-recharge-2",
		CommandID:          "cmd-recharge-2",
		InvitedUserID:      10002,
		AssetType:          "COIN",
		RechargeCoinAmount: 1,
		RechargeType:       invitedomain.RechargeTypeCoinSellerTransfer,
		OccurredAtMs:       4000,
	})
	if err != nil || !duplicate.Skipped || duplicate.Reason != "already_consumed" {
		t.Fatalf("duplicate recharge should be idempotently skipped: result=%+v err=%v", duplicate, err)
	}

	inviter, err = repo.GetUser(ctx, 10001)
	if err != nil {
		t.Fatalf("get inviter after valid failed: %v", err)
	}
	if inviter.InviteOverview.InviteCount != 1 || inviter.InviteOverview.ValidInviteCount != 1 {
		t.Fatalf("valid invite counter mismatch: %+v", inviter.InviteOverview)
	}
}

func createUser(t *testing.T, repo *mysqltest.Repository, userID int64, displayUserID string, nowMs int64) {
	t.Helper()
	if err := repo.CreateUserWithIdentity(context.Background(), userdomain.User{
		AppCode:                  "lalu",
		UserID:                   userID,
		DefaultDisplayUserID:     displayUserID,
		CurrentDisplayUserID:     displayUserID,
		CurrentDisplayUserIDKind: userdomain.DisplayUserIDKindDefault,
		Status:                   userdomain.StatusActive,
		OnboardingStatus:         userdomain.OnboardingStatusProfileRequired,
		CreatedAtMs:              nowMs,
		UpdatedAtMs:              nowMs,
	}, userdomain.Identity{
		AppCode:              "lalu",
		UserID:               userID,
		DisplayUserID:        displayUserID,
		DefaultDisplayUserID: displayUserID,
		DisplayUserIDKind:    userdomain.DisplayUserIDKindDefault,
		Status:               userdomain.DisplayUserIDStatusActive,
	}); err != nil {
		t.Fatalf("create user %d failed: %v", userID, err)
	}
}
