package handlers

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/go-chi/chi/v5"
	"github.com/orchard9/rdev/internal/domain"
	"github.com/orchard9/rdev/internal/port"
	"github.com/orchard9/rdev/internal/sdlc"
	"github.com/orchard9/rdev/internal/service"
)

// testSDLCExecutor implements port.SDLCExecutor for handler tests.
type testSDLCExecutor struct {
	state          *sdlc.State
	classification *sdlc.Classification
	features       []*sdlc.Feature
	feature        *sdlc.Feature
	artifacts      map[sdlc.ArtifactType]*sdlc.Artifact
	tasks          []sdlc.Task
	task           *sdlc.Task
	blocked        []port.BlockedInfo
	ready          []port.ReadyInfo
	approval       []port.ApprovalInfo
	err            error
}

func (m *testSDLCExecutor) GetState(_ context.Context, _ string) (*sdlc.State, error) {
	return m.state, m.err
}
func (m *testSDLCExecutor) GetNext(_ context.Context, _, _ string) (*sdlc.Classification, error) {
	return m.classification, m.err
}
func (m *testSDLCExecutor) ListFeatures(_ context.Context, _ string) ([]*sdlc.Feature, error) {
	return m.features, m.err
}
func (m *testSDLCExecutor) GetFeature(_ context.Context, _, _ string) (*sdlc.Feature, error) {
	return m.feature, m.err
}
func (m *testSDLCExecutor) CreateFeature(_ context.Context, _, slug, title string) (*sdlc.Feature, error) {
	if m.err != nil {
		return nil, m.err
	}
	return &sdlc.Feature{Slug: slug, Title: title, Phase: sdlc.PhaseDraft}, nil
}
func (m *testSDLCExecutor) TransitionFeature(_ context.Context, _, _ string, _ sdlc.FeaturePhase) error {
	return m.err
}
func (m *testSDLCExecutor) BlockFeature(_ context.Context, _, _, _ string) error { return m.err }
func (m *testSDLCExecutor) UnblockFeature(_ context.Context, _, _ string) error  { return m.err }
func (m *testSDLCExecutor) DeleteFeature(_ context.Context, _, _ string) error   { return m.err }
func (m *testSDLCExecutor) GetArtifactStatus(_ context.Context, _, _ string) (map[sdlc.ArtifactType]*sdlc.Artifact, error) {
	return m.artifacts, m.err
}
func (m *testSDLCExecutor) ApproveArtifact(_ context.Context, _, _ string, _ sdlc.ArtifactType) error {
	return m.err
}
func (m *testSDLCExecutor) RejectArtifact(_ context.Context, _, _ string, _ sdlc.ArtifactType) error {
	return m.err
}
func (m *testSDLCExecutor) PassArtifact(_ context.Context, _, _ string, _ sdlc.ArtifactType) error {
	return m.err
}
func (m *testSDLCExecutor) FailArtifact(_ context.Context, _, _ string, _ sdlc.ArtifactType) error {
	return m.err
}
func (m *testSDLCExecutor) NeedsFixArtifact(_ context.Context, _, _ string, _ sdlc.ArtifactType) error {
	return m.err
}
func (m *testSDLCExecutor) ListTasks(_ context.Context, _, _ string) ([]sdlc.Task, error) {
	return m.tasks, m.err
}
func (m *testSDLCExecutor) AddTask(_ context.Context, _, _, title string) (*sdlc.Task, error) {
	if m.err != nil {
		return nil, m.err
	}
	if m.task != nil {
		return m.task, nil
	}
	return &sdlc.Task{ID: "task-001", Title: title, Status: sdlc.TaskPending}, nil
}
func (m *testSDLCExecutor) StartTask(_ context.Context, _, _, _ string) error    { return m.err }
func (m *testSDLCExecutor) CompleteTask(_ context.Context, _, _, _ string) error { return m.err }
func (m *testSDLCExecutor) BlockTask(_ context.Context, _, _, _ string) error    { return m.err }
func (m *testSDLCExecutor) QueryBlocked(_ context.Context, _ string) ([]port.BlockedInfo, error) {
	return m.blocked, m.err
}
func (m *testSDLCExecutor) QueryReady(_ context.Context, _ string) ([]port.ReadyInfo, error) {
	return m.ready, m.err
}
func (m *testSDLCExecutor) QueryNeedsApproval(_ context.Context, _ string) ([]port.ApprovalInfo, error) {
	return m.approval, m.err
}
func (m *testSDLCExecutor) CreateBranch(_ context.Context, _, slug string) (*sdlc.BranchManifest, error) {
	if m.err != nil {
		return nil, m.err
	}
	return &sdlc.BranchManifest{Name: "feature/" + slug, Feature: slug}, nil
}
func (m *testSDLCExecutor) GetBranchStatus(_ context.Context, _, slug string) (*port.BranchStatus, error) {
	if m.err != nil {
		return nil, m.err
	}
	return &port.BranchStatus{
		Branch:    &sdlc.BranchManifest{Name: "feature/" + slug, Feature: slug},
		Checklist: nil,
		Ready:     true,
	}, nil
}
func (m *testSDLCExecutor) SyncBranch(_ context.Context, _, _ string) error      { return m.err }
func (m *testSDLCExecutor) MergeFeature(_ context.Context, _, _, _ string) error { return m.err }
func (m *testSDLCExecutor) ArchiveFeature(_ context.Context, _, _ string) error  { return m.err }

// testSDLCProjectRepo implements port.ProjectRepository for handler tests.
type testSDLCProjectRepo struct {
	project *domain.Project
}

func (m *testSDLCProjectRepo) Get(_ context.Context, _ domain.ProjectID) (*domain.Project, error) {
	if m.project == nil {
		return nil, domain.ErrProjectNotFound
	}
	return m.project, nil
}
func (m *testSDLCProjectRepo) List(_ context.Context) ([]domain.Project, error) { return nil, nil }
func (m *testSDLCProjectRepo) Exists(_ context.Context, _ domain.ProjectID) (bool, error) {
	return m.project != nil, nil
}
func (m *testSDLCProjectRepo) Register(_ context.Context, _ *domain.Project) error    { return nil }
func (m *testSDLCProjectRepo) Unregister(_ context.Context, _ domain.ProjectID) error { return nil }
func (m *testSDLCProjectRepo) RefreshStatus(_ context.Context) error                  { return nil }

func setupSDLCHandler(exec *testSDLCExecutor) (*SDLCHandler, *chi.Mux) {
	repo := &testSDLCProjectRepo{
		project: &domain.Project{ID: "test-project", PodName: "test-pod"},
	}
	svc := service.NewSDLCService(exec, repo)
	handler := NewSDLCHandler(svc)
	r := chi.NewRouter()
	r.Use(testAdminAuth)
	handler.Mount(r)
	return handler, r
}

func TestSDLCHandler_GetState(t *testing.T) {
	exec := &testSDLCExecutor{
		state: &sdlc.State{Version: 1},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/state", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_GetState_NotInitialized(t *testing.T) {
	exec := &testSDLCExecutor{
		err: sdlc.ErrNotInitialized,
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/state", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_GetState_ProjectNotFound(t *testing.T) {
	exec := &testSDLCExecutor{}
	repo := &testSDLCProjectRepo{project: nil}
	svc := service.NewSDLCService(exec, repo)
	handler := NewSDLCHandler(svc)
	r := chi.NewRouter()
	r.Use(testAdminAuth)
	handler.Mount(r)

	req := httptest.NewRequest(http.MethodGet, "/projects/nonexistent/sdlc/state", nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_CreateFeature(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(CreateFeatureRequest{Slug: "auth-flow", Title: "Auth Flow"})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusCreated {
		t.Errorf("expected status 201, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_CreateFeature_MissingFields(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(CreateFeatureRequest{})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_CreateFeature_AlreadyExists(t *testing.T) {
	exec := &testSDLCExecutor{err: sdlc.ErrFeatureExists}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(CreateFeatureRequest{Slug: "auth-flow", Title: "Auth Flow"})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_TransitionFeature(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(TransitionFeatureRequest{Phase: "specified"})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/transition", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_TransitionFeature_InvalidPhase(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(TransitionFeatureRequest{Phase: "not-a-phase"})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/transition", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_TransitionFeature_InvalidTransition(t *testing.T) {
	exec := &testSDLCExecutor{err: sdlc.ErrInvalidTransition}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(TransitionFeatureRequest{Phase: "review"})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/transition", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_BlockFeature(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(BlockFeatureRequest{Reason: "needs API key"})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/block", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_BlockFeature_MissingReason(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(BlockFeatureRequest{})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/block", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_DeleteFeature(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodDelete, "/projects/test-project/sdlc/features/auth-flow", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNoContent {
		t.Errorf("expected status 204, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_DeleteFeature_NotFound(t *testing.T) {
	exec := &testSDLCExecutor{err: sdlc.ErrFeatureNotFound}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodDelete, "/projects/test-project/sdlc/features/nonexistent", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_ApproveArtifact(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/artifacts/spec/approve", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_ApproveArtifact_InvalidType(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/artifacts/invalid/approve", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_AddTask(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(AddTaskRequest{Title: "Add login form"})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/tasks", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusCreated {
		t.Errorf("expected status 201, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_AddTask_MissingTitle(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	body, _ := json.Marshal(AddTaskRequest{})
	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/tasks", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_QueryBlocked(t *testing.T) {
	exec := &testSDLCExecutor{
		blocked: []port.BlockedInfo{
			{Slug: "auth", Phase: "implementation", Blockers: []string{"needs API key"}},
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/query/blocked", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_InternalError(t *testing.T) {
	exec := &testSDLCExecutor{err: errors.New("something unexpected")}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/state", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusInternalServerError {
		t.Errorf("expected status 500, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_GetNext(t *testing.T) {
	exec := &testSDLCExecutor{
		classification: &sdlc.Classification{
			Feature:      "auth-flow",
			CurrentPhase: sdlc.PhaseDraft,
			RuleMatched:  "needs-spec",
			Action:       sdlc.ActionCreateSpec,
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/next?feature=auth-flow", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_GetNext_FeatureNotFound(t *testing.T) {
	exec := &testSDLCExecutor{err: sdlc.ErrFeatureNotFound}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/next?feature=nonexistent", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_ListFeatures(t *testing.T) {
	exec := &testSDLCExecutor{
		features: []*sdlc.Feature{
			{Slug: "auth-flow", Title: "Auth Flow", Phase: sdlc.PhaseDraft},
			{Slug: "payments", Title: "Payments", Phase: sdlc.PhaseImplementation},
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/features", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_ListFeatures_Empty(t *testing.T) {
	exec := &testSDLCExecutor{features: nil}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/features", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
	// Should return empty array, not null
	if w.Body.String() == "null" {
		t.Error("expected empty array, not null")
	}
}

func TestSDLCHandler_GetFeature(t *testing.T) {
	exec := &testSDLCExecutor{
		feature: &sdlc.Feature{
			Slug:  "auth-flow",
			Title: "Auth Flow",
			Phase: sdlc.PhaseDraft,
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/features/auth-flow", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_GetFeature_NotFound(t *testing.T) {
	exec := &testSDLCExecutor{err: sdlc.ErrFeatureNotFound}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/features/nonexistent", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_UnblockFeature(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/unblock", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_UnblockFeature_NotFound(t *testing.T) {
	exec := &testSDLCExecutor{err: sdlc.ErrFeatureNotFound}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/nonexistent/unblock", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_RejectArtifact(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/artifacts/spec/reject", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_RejectArtifact_InvalidType(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/artifacts/invalid/reject", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_GetArtifactStatus(t *testing.T) {
	exec := &testSDLCExecutor{
		artifacts: map[sdlc.ArtifactType]*sdlc.Artifact{
			sdlc.ArtifactSpec:   sdlc.NewArtifact(sdlc.ArtifactSpec),
			sdlc.ArtifactDesign: sdlc.NewArtifact(sdlc.ArtifactDesign),
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/features/auth-flow/artifacts", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_ListTasks(t *testing.T) {
	exec := &testSDLCExecutor{
		tasks: []sdlc.Task{
			{ID: "task-001", Title: "Setup auth", Status: sdlc.TaskPending},
			{ID: "task-002", Title: "Add login", Status: sdlc.TaskInProgress},
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/features/auth-flow/tasks", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_StartTask(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/tasks/task-001/start", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_StartTask_NotFound(t *testing.T) {
	exec := &testSDLCExecutor{err: sdlc.ErrTaskNotFound}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/tasks/nonexistent/start", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_CompleteTask(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/tasks/task-001/complete", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_BlockTask(t *testing.T) {
	exec := &testSDLCExecutor{}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/features/auth-flow/tasks/task-001/block", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_QueryReady(t *testing.T) {
	exec := &testSDLCExecutor{
		ready: []port.ReadyInfo{
			{Slug: "auth", Phase: "ready", Action: "IMPLEMENT_TASK"},
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/query/ready", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}

func TestSDLCHandler_QueryNeedsApproval(t *testing.T) {
	exec := &testSDLCExecutor{
		approval: []port.ApprovalInfo{
			{Slug: "auth", Phase: "draft", Message: "spec requires approval"},
		},
	}
	_, router := setupSDLCHandler(exec)

	req := httptest.NewRequest(http.MethodGet, "/projects/test-project/sdlc/query/needs-approval", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String())
	}
}
