package usecase

import (
	"context"

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

	"github.com/google/uuid"
)

func (s *Service) GetRun(ctx context.Context, ownerUID int64, runID string) (*domain.Run, error) {
	if s == nil || s.Repo == nil || runID == "" {
		return nil, domain.ErrValidation
	}
	return s.Repo.GetRun(ctx, ownerUID, runID)
}

// CreateQueuedRun creates one independent run for every scan request. The
// job_id is bound in a second guarded write after job scheduling succeeds.
func (s *Service) CreateQueuedRun(ctx context.Context, ownerUID int64, brief *domain.RunBrief) (*domain.Run, error) {
	if s == nil || s.Repo == nil || brief == nil || ownerUID == 0 {
		return nil, domain.ErrValidation
	}
	run := domain.NewRun("run_"+uuid.NewString(), "", ownerUID, *brief, domain.NowNano())
	if err := s.Repo.CreateRun(ctx, run); err != nil {
		return nil, err
	}
	return run, nil
}

func (s *Service) BindRunJob(ctx context.Context, ownerUID int64, runID, jobID string) (*domain.Run, error) {
	if s == nil || s.Repo == nil || runID == "" || jobID == "" {
		return nil, domain.ErrValidation
	}
	run, err := s.Repo.GetRun(ctx, ownerUID, runID)
	if err != nil {
		return nil, err
	}
	if run.JobID != "" && run.JobID != jobID {
		return nil, domain.ErrIllegalRunStatus
	}
	run.JobID = jobID
	if err := s.Repo.ReplaceRunGuarded(ctx, ownerUID, runID, []string{domain.RunQueued}, run); err != nil {
		return nil, err
	}
	return run, nil
}

// ListRuns returns only runs owned by ownerUID. Pagination is normalized here
// so every caller (HTTP, worker and tests) observes the same page contract.
func (s *Service) ListRuns(ctx context.Context, ownerUID int64, brandID, mode string, page, pageSize int) (domain.RunPage, error) {
	if s == nil || s.Repo == nil {
		return domain.RunPage{}, domain.ErrValidation
	}
	pageInfo := domain.NormalizePage(page, pageSize)
	return s.Repo.ListRuns(ctx, domain.RunFilter{
		OwnerUID: ownerUID,
		BrandID:  brandID,
		Mode:     mode,
		Page:     pageInfo.Page,
		PageSize: pageInfo.PageSize,
	})
}

// ListRunPosts returns the selected run and its independently paged results.
// Repository implementations hide staged results until the run succeeds.
func (s *Service) ListRunPosts(ctx context.Context, ownerUID int64, runID string, page, pageSize int) (domain.RunPostPage, error) {
	if s == nil || s.Repo == nil {
		return domain.RunPostPage{}, domain.ErrValidation
	}
	if runID == "" {
		return domain.RunPostPage{}, domain.ErrValidation
	}
	pageInfo := domain.NormalizePage(page, pageSize)
	return s.Repo.ListRunPosts(ctx, ownerUID, runID, pageInfo.Page, pageInfo.PageSize)
}

// RemoveRun only permits terminal runs to be removed. Returning the same
// guarded transition error for queued/running keeps the API from exposing
// implementation details while allowing response mapping to a 409 conflict.
func (s *Service) RemoveRun(ctx context.Context, ownerUID int64, runID string) error {
	if s == nil || s.Repo == nil {
		return domain.ErrValidation
	}
	if runID == "" {
		return domain.ErrValidation
	}
	r, err := s.Repo.GetRun(ctx, ownerUID, runID)
	if err != nil {
		return err
	}
	if !domain.IsRunTerminal(r.Status) {
		return domain.ErrIllegalRunStatus
	}
	return s.Repo.DeleteRun(ctx, ownerUID, runID)
}
