package mysql

import (
	"context"
	"testing"

	"hyapp/internal/testutil/mysqlschema"
	"hyapp/pkg/appcode"
	domain "hyapp/services/activity-service/internal/domain/agencyopening"
)

func TestAgencyOpeningScoresOnlyAfterApprovalWithinWindow(t *testing.T) {
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "ACTIVITY_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, mysqlschema.CallerFile(t, 1), "..", "..", "..", "deploy", "mysql", "initdb", "001_activity_service.sql"),
		DatabasePrefix: "hyapp_activity_agency_opening_test",
	})
	repository, err := Open(context.Background(), schema.DSN)
	if err != nil {
		t.Fatalf("open repository: %v", err)
	}
	t.Cleanup(func() { _ = repository.Close() })

	ctx := appcode.WithContext(context.Background(), "lalu")
	const (
		cycleID       = "cycle-window"
		applicationID = "application-window"
		ownerUserID   = int64(42001)
		nowMS         = int64(10_000)
	)
	_, err = repository.db.ExecContext(ctx, `
		INSERT INTO agency_opening_cycles (
			app_code, region_id, cycle_id, activity_code, title, status, start_ms, end_ms, min_host_count, max_agency_age_days,
			created_by_admin_id, updated_by_admin_id, settled_at_ms, locked_by, lock_until_ms, created_at_ms, updated_at_ms
		) VALUES ('lalu', 12, ?, ?, 'window test', ?, 1, ?, 10, 30, 1, 1, 0, '', 0, ?, ?)`,
		cycleID, domain.ActivityCode, domain.StatusActive, nowMS+int64((48*60*60*1000)), nowMS, nowMS,
	)
	if err != nil {
		t.Fatalf("seed cycle: %v", err)
	}
	_, err = repository.db.ExecContext(ctx, `
		INSERT INTO agency_opening_applications (
			app_code, region_id, application_id, cycle_id, agency_id, agency_owner_user_id, agency_name, host_count, agency_created_at_ms,
			status, score_coin_amount, reward_rank_no, reward_threshold_coin_spent, reward_coin_amount,
			wallet_command_id, wallet_transaction_id, failure_reason, applied_at_ms, approved_at_ms,
			score_start_ms, score_end_ms, reviewed_by_admin_id, granted_at_ms, created_at_ms, updated_at_ms
		) VALUES ('lalu', 12, ?, ?, 8001, ?, 'Window Agency', 12, 1, ?, 0, 0, 0, 0, '', '', '', ?, 0, 0, 0, 0, 0, ?, ?)`,
		applicationID, cycleID, ownerUserID, domain.ApplicationStatusApplied, nowMS-1000, nowMS, nowMS,
	)
	if err != nil {
		t.Fatalf("seed application: %v", err)
	}

	beforeApproval, err := repository.ConsumeAgencyOpeningGiftEvent(ctx, domain.GiftEvent{
		EventID:         "gift-before-approval",
		RegionID:        12,
		RoomOwnerUserID: ownerUserID,
		TargetUserID:    99,
		CoinSpent:       700,
		OccurredAtMS:    nowMS + 100,
	}, nowMS+100)
	if err != nil {
		t.Fatalf("consume before approval: %v", err)
	}
	if beforeApproval.Status != domain.EventStatusSkipped {
		t.Fatalf("event before approval must be skipped, got %s", beforeApproval.Status)
	}

	approved, err := repository.ApproveAgencyOpeningApplication(ctx, applicationID, 77, nowMS+200)
	if err != nil {
		t.Fatalf("approve application: %v", err)
	}
	wantScoreEnd := nowMS + 200 + int64((24 * 60 * 60 * 1000))
	if approved.Status != domain.ApplicationStatusApproved || approved.ScoreStartMS != nowMS+200 || approved.ScoreEndMS != wantScoreEnd || approved.ReviewedByAdminID != 77 {
		t.Fatalf("unexpected approved application: %+v", approved)
	}

	otherRegion, err := repository.ConsumeAgencyOpeningGiftEvent(ctx, domain.GiftEvent{
		EventID:         "gift-other-region",
		RegionID:        13,
		RoomOwnerUserID: ownerUserID,
		TargetUserID:    100,
		CoinSpent:       800,
		OccurredAtMS:    nowMS + 250,
	}, nowMS+250)
	if err != nil {
		t.Fatalf("consume other-region gift: %v", err)
	}
	if otherRegion.Status != domain.EventStatusSkipped {
		t.Fatalf("gift from another region must not score, got %s", otherRegion.Status)
	}

	insideWindow, err := repository.ConsumeAgencyOpeningGiftEvent(ctx, domain.GiftEvent{
		EventID:         "gift-inside-window",
		RegionID:        12,
		RoomOwnerUserID: ownerUserID,
		TargetUserID:    100,
		CoinSpent:       900,
		OccurredAtMS:    nowMS + 300,
	}, nowMS+300)
	if err != nil {
		t.Fatalf("consume inside window: %v", err)
	}
	if insideWindow.Status != domain.EventStatusConsumed {
		t.Fatalf("event inside approved window must be consumed, got %s", insideWindow.Status)
	}

	afterWindow, err := repository.ConsumeAgencyOpeningGiftEvent(ctx, domain.GiftEvent{
		EventID:         "gift-after-window",
		RegionID:        12,
		RoomOwnerUserID: ownerUserID,
		TargetUserID:    101,
		CoinSpent:       1200,
		OccurredAtMS:    wantScoreEnd,
	}, wantScoreEnd)
	if err != nil {
		t.Fatalf("consume after window: %v", err)
	}
	if afterWindow.Status != domain.EventStatusSkipped {
		t.Fatalf("event at score_end must be skipped, got %s", afterWindow.Status)
	}

	var score int64
	if err := repository.db.QueryRowContext(ctx, `
		SELECT score_coin_amount FROM agency_opening_applications
		WHERE app_code = 'lalu' AND application_id = ?`, applicationID).Scan(&score); err != nil {
		t.Fatalf("read final score: %v", err)
	}
	if score != 900 {
		t.Fatalf("only the inside-window event should score, got %d", score)
	}
}
