package region_test

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

	"hyapp/pkg/appcode"
	userdomain "hyapp/services/user-service/internal/domain/user"
	"hyapp/services/user-service/internal/testutil/mysqltest"
)

func TestProcessRegionRebuildTaskWritesUserRegionChangedOutbox(t *testing.T) {
	ctx := appcode.WithContext(context.Background(), appcode.Default)
	repository := mysqltest.NewRepository(t)
	repository.PutCountry(userdomain.Country{CountryCode: "US", Enabled: true})
	repository.PutRegion(userdomain.Region{RegionID: 301, RegionCode: "OLD-US", Name: "Old US", Countries: []string{"US"}})
	repository.PutRegion(userdomain.Region{RegionID: 302, RegionCode: "NEW-US", Name: "New US", Countries: []string{"US"}})
	repository.PutUser(userdomain.User{
		UserID:               93001,
		DefaultDisplayUserID: "93001",
		CurrentDisplayUserID: "93001",
		Country:              "US",
		RegionID:             301,
		ProfileCompleted:     true,
		OnboardingStatus:     userdomain.OnboardingStatusCompleted,
		Status:               userdomain.StatusActive,
	})
	repository.PutUser(userdomain.User{
		UserID:               93002,
		DefaultDisplayUserID: "93002",
		CurrentDisplayUserID: "93002",
		Country:              "US",
		RegionID:             302,
		ProfileCompleted:     true,
		OnboardingStatus:     userdomain.OnboardingStatusCompleted,
		Status:               userdomain.StatusActive,
	})
	if _, err := repository.RawDB().ExecContext(ctx, `DELETE FROM user_region_rebuild_tasks WHERE app_code = ?`, appcode.Default); err != nil {
		t.Fatalf("clear seeded rebuild tasks failed: %v", err)
	}
	nowMS := int64(1_700_000_456_000)
	if _, err := repository.RawDB().ExecContext(ctx, `
		INSERT INTO user_region_rebuild_tasks (app_code, region_id, country_code, target_region_id, mapping_revision, status, cursor_user_id, created_at_ms, updated_at_ms)
		VALUES (?, ?, 'US', ?, ?, ?, 0, ?, ?)
	`, appcode.Default, int64(302), int64(302), nowMS, userdomain.RegionRebuildTaskStatusPending, nowMS, nowMS); err != nil {
		t.Fatalf("insert rebuild task failed: %v", err)
	}

	result, err := repository.ProcessNextRegionRebuildTask(ctx, "region-test-worker", nowMS+1, time.Minute, 10)
	if err != nil {
		t.Fatalf("ProcessNextRegionRebuildTask failed: %v", err)
	}
	if result.ProcessedUsers != 2 || result.Status != userdomain.RegionRebuildTaskStatusCompleted {
		t.Fatalf("rebuild result mismatch: %+v", result)
	}

	var changedRegionID int64
	if err := repository.RawDB().QueryRowContext(ctx, `SELECT COALESCE(region_id, 0) FROM users WHERE app_code = ? AND user_id = ?`, appcode.Default, int64(93001)).Scan(&changedRegionID); err != nil {
		t.Fatalf("query changed user failed: %v", err)
	}
	if changedRegionID != 302 {
		t.Fatalf("changed user region mismatch: %d", changedRegionID)
	}
	var outboxCount int
	var payloadJSON string
	if err := repository.RawDB().QueryRowContext(ctx, `
		SELECT COUNT(*), COALESCE(MAX(CAST(payload_json AS CHAR)), '')
		FROM user_outbox
		WHERE app_code = ? AND event_type = 'UserRegionChanged'
	`, appcode.Default).Scan(&outboxCount, &payloadJSON); err != nil {
		t.Fatalf("query region rebuild outbox failed: %v", err)
	}
	if outboxCount != 1 {
		t.Fatalf("only changed users should write region outbox, count=%d", outboxCount)
	}
	var payload map[string]any
	if err := json.Unmarshal([]byte(payloadJSON), &payload); err != nil {
		t.Fatalf("decode outbox payload failed: %v", err)
	}
	if payload["source"] != "region_rebuild" || int64(payload["user_id"].(float64)) != 93001 || int64(payload["old_region_id"].(float64)) != 301 || int64(payload["new_region_id"].(float64)) != 302 {
		t.Fatalf("region rebuild payload mismatch: %v", payload)
	}
}
