package usecase

import (
	"context"
	"errors"
	"testing"

	"apps/backend/internal/module/scout/domain"
	"apps/backend/internal/module/scout/repository"
)

func TestRunPublishVisibilityBarrierAndCounters(t *testing.T) {
	ctx := context.Background()
	store := repository.NewMemory()
	run := domain.NewRun("run-publish", "job-publish", 7, domain.RunBrief{
		Intent: "市集", Mode: domain.ModeActivity, TargetCount: 3,
	}, 100)
	if err := store.CreateRun(ctx, run); err != nil {
		t.Fatal(err)
	}
	if err := run.Transition(domain.RunRunning, 200); err != nil {
		t.Fatal(err)
	}
	if err := store.ReplaceRunGuarded(ctx, 7, run.ID, []string{domain.RunQueued}, run); err != nil {
		t.Fatal(err)
	}
	svc := New(store)
	posts := []*domain.Post{
		{ID: "publish-new", RunID: run.ID, OwnerUID: 7, OutreachStatus: domain.OutreachNew, PostedAt: 200, CreatedAt: 20},
		{ID: "publish-old", RunID: run.ID, OwnerUID: 7, OutreachStatus: domain.OutreachDrafted, PostedAt: 100, CreatedAt: 10},
	}
	if err := svc.StageRunPosts(ctx, 7, run.ID, posts); err != nil {
		t.Fatal(err)
	}
	staged, err := store.ListRunPosts(ctx, 7, run.ID, 1, 10)
	if err != nil || staged.Pagination.Total != 0 || len(staged.Items) != 0 {
		t.Fatalf("staged posts leaked: %+v %v", staged, err)
	}
	if err := svc.PublishRun(ctx, 7, run.ID, posts); err != nil {
		t.Fatal(err)
	}
	visible, err := store.ListRunPosts(ctx, 7, run.ID, 1, 10)
	if err != nil || visible.Pagination.Total != 2 || len(visible.Items) != 2 || visible.Items[0].ID != "publish-new" {
		t.Fatalf("published results=%+v %v", visible, err)
	}
	got, err := store.GetRun(ctx, 7, run.ID)
	if err != nil || got.Status != domain.RunSucceeded || got.EligibleCount != 2 || got.PendingCount != 2 || got.ShortfallCount != 1 {
		t.Fatalf("published run=%+v %v", got, err)
	}
	seen, err := store.HasSeenIdentity(ctx, 7, "id:publish-new")
	if err != nil || !seen {
		t.Fatalf("published identity not marked: %v %v", seen, err)
	}
}

func TestRunPublishFailureLeavesResultsHiddenAndTerminalGuard(t *testing.T) {
	ctx := context.Background()
	store := repository.NewMemory()
	run := domain.NewRun("run-fail", "job-fail", 7, domain.RunBrief{Intent: "市集", Mode: domain.ModeActivity}, 100)
	if err := store.CreateRun(ctx, run); err != nil {
		t.Fatal(err)
	}
	if err := run.Transition(domain.RunRunning, 200); err != nil {
		t.Fatal(err)
	}
	if err := store.ReplaceRunGuarded(ctx, 7, run.ID, []string{domain.RunQueued}, run); err != nil {
		t.Fatal(err)
	}
	svc := New(store)
	posts := []*domain.Post{{ID: "hidden", RunID: run.ID, OwnerUID: 7}}
	if err := svc.StageRunPosts(ctx, 7, run.ID, posts); err != nil {
		t.Fatal(err)
	}
	if err := svc.FailRun(ctx, 7, run.ID, "provider timeout"); err != nil {
		t.Fatal(err)
	}
	page, err := store.ListRunPosts(ctx, 7, run.ID, 1, 10)
	if err != nil || page.Pagination.Total != 0 || len(page.Items) != 0 {
		t.Fatalf("failed run exposed posts: %+v %v", page, err)
	}
	failed, err := store.GetRun(ctx, 7, run.ID)
	if err != nil || failed.Status != domain.RunFailed || failed.Error != "provider timeout" {
		t.Fatalf("failed run=%+v %v", failed, err)
	}
	if err := svc.FailRun(ctx, 7, run.ID, "retry"); err != nil {
		t.Fatal(err)
	}
	if err := svc.StageRunPosts(ctx, 7, run.ID, posts); !errors.Is(err, domain.ErrIllegalRunStatus) {
		t.Fatalf("terminal stage error=%v", err)
	}
}
