package service

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/orchard9/rdev/internal/domain"
	"github.com/orchard9/rdev/internal/logging"
)

// SDLCGenerateService handles async artifact generation via the work queue.
type SDLCGenerateService struct {
	sdlcService  *SDLCService
	buildService *BuildService
	db           *sql.DB
	baseURL      string
}

// SDLCGenerateServiceConfig configures the generate service.
type SDLCGenerateServiceConfig struct {
	// BaseURL is the API base URL for callback URLs (e.g., "http://localhost:8080")
	BaseURL string
}

// NewSDLCGenerateService creates a new SDLC generate service.
func NewSDLCGenerateService(
	sdlcService *SDLCService,
	buildService *BuildService,
	db *sql.DB,
	cfg SDLCGenerateServiceConfig,
) *SDLCGenerateService {
	return &SDLCGenerateService{
		sdlcService:  sdlcService,
		buildService: buildService,
		db:           db,
		baseURL:      cfg.BaseURL,
	}
}

// GenerateArtifact enqueues a build task to generate an SDLC artifact.
func (s *SDLCGenerateService) GenerateArtifact(
	ctx context.Context,
	projectID, featureSlug string,
	req *domain.SDLCGenerateRequest,
) (*domain.SDLCGenerateResponse, error) {
	// Validate artifact type
	if !domain.IsValidGenerateArtifactType(req.ArtifactType) {
		return nil, fmt.Errorf("invalid artifact_type: %s", req.ArtifactType)
	}

	// Validate task_id is provided for code generation
	if req.ArtifactType == "code" && req.TaskID == "" {
		return nil, fmt.Errorf("task_id is required for artifact_type: code")
	}

	// Validate feature exists
	_, err := s.sdlcService.GetFeature(ctx, projectID, featureSlug)
	if err != nil {
		return nil, fmt.Errorf("get feature: %w", err)
	}

	// Get project git URL from database
	gitCloneURL, err := s.getProjectGitURL(ctx, projectID)
	if err != nil {
		return nil, fmt.Errorf("get project git URL: %w", err)
	}

	// Build the prompt from artifact type
	prompt := s.buildPrompt(featureSlug, req.ArtifactType, req.TaskID)

	// Build callback URL for SDLC status updates
	callbackURL := s.baseURL + "/internal/sdlc/callback"

	// Create build spec with SDLC context
	buildSpec := domain.BuildSpec{
		Prompt:      prompt,
		AutoCommit:  true,
		AutoPush:    true,
		GitCloneURL: gitCloneURL,
		CallbackURL: callbackURL,
	}

	// Build SDLC context map for callback routing
	sdlcContext := map[string]any{
		"feature":       featureSlug,
		"artifact_type": req.ArtifactType,
	}
	if req.TaskID != "" {
		sdlcContext["task_id"] = req.TaskID
	}

	taskID, err := s.buildService.StartBuildWithSDLCContext(ctx, projectID, buildSpec, sdlcContext)
	if err != nil {
		return nil, fmt.Errorf("start build: %w", err)
	}

	log := logging.FromContext(ctx).WithService("sdlc_generate")
	log.Info("artifact generation enqueued",
		logging.FieldProjectID, projectID,
		"feature", featureSlug,
		"artifact_type", req.ArtifactType,
		"task_id", taskID,
	)

	return &domain.SDLCGenerateResponse{
		TaskID:       taskID,
		ProjectID:    projectID,
		Feature:      featureSlug,
		ArtifactType: req.ArtifactType,
		Status:       "pending",
		StatusURL:    "/builds/" + taskID,
		StreamURL:    fmt.Sprintf("/projects/%s/events?stream_id=%s", projectID, taskID),
	}, nil
}

// buildPrompt constructs the appropriate skeleton command for the artifact type.
func (s *SDLCGenerateService) buildPrompt(feature, artifactType, taskID string) string {
	switch artifactType {
	case "spec":
		return "/spec-feature " + feature
	case "design":
		return "/design-feature " + feature
	case "tasks":
		return "/breakdown-feature " + feature
	case "code":
		if taskID != "" {
			return "/implement-task " + feature + " " + taskID
		}
		return "/implement-feature " + feature
	case "qa":
		return "/run-qa " + feature
	default:
		return fmt.Sprintf("Generate %s artifact for feature %s", artifactType, feature)
	}
}

// getProjectGitURL retrieves the git clone URL for a project from the database.
func (s *SDLCGenerateService) getProjectGitURL(ctx context.Context, projectID string) (string, error) {
	if s.db == nil {
		return "", fmt.Errorf("database not configured")
	}

	var gitCloneHTTP sql.NullString
	err := s.db.QueryRowContext(ctx,
		`SELECT git_clone_http FROM projects WHERE id = $1`,
		projectID,
	).Scan(&gitCloneHTTP)
	if err != nil {
		if err == sql.ErrNoRows {
			return "", domain.ErrProjectNotFound
		}
		return "", fmt.Errorf("query project: %w", err)
	}

	if !gitCloneHTTP.Valid || gitCloneHTTP.String == "" {
		return "", fmt.Errorf("project %s has no git URL configured", projectID)
	}

	return gitCloneHTTP.String, nil
}
