package storage

import (
	"context"
	"errors"

	"github.com/nomadcode/nomadcode-core/internal/db"
)

// RoadmapSyncStep is the closed set of creation-cycle steps tracked in the
// ledger, in execution order. A completed step is skipped on re-process so a
// partially-failed cycle resumes only the remaining steps.
type RoadmapSyncStep string

const (
	StepDevelopMatched           RoadmapSyncStep = "develop_matched"
	StepOriginalCommentPreserved RoadmapSyncStep = "original_comment_preserved"
	StepPlaneBodyUpdated         RoadmapSyncStep = "plane_body_updated"
	StepPlaneTodoMoved           RoadmapSyncStep = "plane_todo_moved"
)

// OrderedRoadmapSyncSteps lists the steps in the order the creation cycle runs
// them, so a resume can pick the first not-yet-completed step.
var OrderedRoadmapSyncSteps = []RoadmapSyncStep{
	StepDevelopMatched,
	StepOriginalCommentPreserved,
	StepPlaneBodyUpdated,
	StepPlaneTodoMoved,
}

// ErrUnknownRoadmapSyncStep is returned when a caller marks or queries a step
// outside the closed set, mirroring the DB check constraint so a typo never
// silently records an unknown step.
var ErrUnknownRoadmapSyncStep = errors.New("unknown roadmap sync step")

// Valid reports whether the step is part of the tracked closed set.
func (s RoadmapSyncStep) Valid() bool {
	switch s {
	case StepDevelopMatched, StepOriginalCommentPreserved, StepPlaneBodyUpdated, StepPlaneTodoMoved:
		return true
	default:
		return false
	}
}

// MarkStepCompleted records that a step finished for an identity. Re-marking an
// already-completed step is a no-op that returns the existing row, so a retry
// after a later-step failure never duplicates ledger rows. An unknown step is
// rejected before touching the DB.
func (s *Store) MarkStepCompleted(ctx context.Context, identityID int64, step RoadmapSyncStep) (db.RoadmapSyncStep, error) {
	if !step.Valid() {
		return db.RoadmapSyncStep{}, ErrUnknownRoadmapSyncStep
	}
	return s.queries.MarkRoadmapSyncStepCompleted(ctx, db.MarkRoadmapSyncStepCompletedParams{
		RoadmapSyncIdentityID: identityID,
		Step:                  string(step),
	})
}

// CompletedSteps returns the set of steps already completed for an identity, so
// a retry decision can skip them.
func (s *Store) CompletedSteps(ctx context.Context, identityID int64) (map[RoadmapSyncStep]bool, error) {
	rows, err := s.queries.ListRoadmapSyncSteps(ctx, identityID)
	if err != nil {
		return nil, err
	}
	done := make(map[RoadmapSyncStep]bool, len(rows))
	for _, r := range rows {
		done[RoadmapSyncStep(r.Step)] = true
	}
	return done, nil
}
