// cmd_bootstrap.go implements bootstrap mode for new workspaces.
//
// Bootstrap mode is activated when no repos.yaml exists in the current
// directory or any parent. It clones core-devops first, then uses its
// repos.yaml to present the package wizard.

package setup

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/host-uk/core/internal/cmd/workspace"
	"github.com/host-uk/core/pkg/i18n"
	coreio "github.com/host-uk/core/pkg/io"
	"github.com/host-uk/core/pkg/repos"
)

// runSetupOrchestrator decides between registry mode and bootstrap mode.
func runSetupOrchestrator(registryPath, only string, dryRun, all bool, projectName string, runBuild bool) error {
	ctx := context.Background()

	// Try to find an existing registry
	var foundRegistry string
	var err error

	if registryPath != "" {
		foundRegistry = registryPath
	} else {
		foundRegistry, err = repos.FindRegistry(coreio.Local)
	}

	// If registry exists, use registry mode
	if err == nil && foundRegistry != "" {
		return runRegistrySetup(ctx, foundRegistry, only, dryRun, all, runBuild)
	}

	// No registry found - enter bootstrap mode
	return runBootstrap(ctx, only, dryRun, all, projectName, runBuild)
}

// runBootstrap handles the case where no repos.yaml exists.
func runBootstrap(ctx context.Context, only string, dryRun, all bool, projectName string, runBuild bool) error {
	cwd, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("failed to get working directory: %w", err)
	}

	fmt.Printf("%s %s\n", dimStyle.Render(">>"), i18n.T("cmd.setup.bootstrap_mode"))

	var targetDir string

	// Check if current directory is empty
	empty, err := isDirEmpty(cwd)
	if err != nil {
		return fmt.Errorf("failed to check directory: %w", err)
	}

	if empty {
		// Clone into current directory
		targetDir = cwd
		fmt.Printf("%s %s\n", dimStyle.Render(">>"), i18n.T("cmd.setup.cloning_current_dir"))
	} else {
		// Directory has content - check if it's a git repo root
		isRepo := isGitRepoRoot(cwd)

		if isRepo && isTerminal() && !all {
			// Offer choice: setup working directory or create package
			choice, err := promptSetupChoice()
			if err != nil {
				return fmt.Errorf("failed to get choice: %w", err)
			}

			if choice == "setup" {
				// Setup this working directory with .core/ config
				return runRepoSetup(cwd, dryRun)
			}
			// Otherwise continue to "create package" flow
		}

		// Create package flow - need a project name
		if projectName == "" {
			if !isTerminal() || all {
				projectName = defaultOrg
			} else {
				projectName, err = promptProjectName(defaultOrg)
				if err != nil {
					return fmt.Errorf("failed to get project name: %w", err)
				}
			}
		}

		targetDir = filepath.Join(cwd, projectName)
		fmt.Printf("%s %s: %s\n", dimStyle.Render(">>"), i18n.T("cmd.setup.creating_project_dir"), projectName)

		if !dryRun {
			if err := coreio.Local.EnsureDir(targetDir); err != nil {
				return fmt.Errorf("failed to create directory: %w", err)
			}
		}
	}

	// Clone core-devops first
	devopsPath := filepath.Join(targetDir, devopsRepo)
	if !coreio.Local.Exists(filepath.Join(devopsPath, ".git")) {
		fmt.Printf("%s %s %s...\n", dimStyle.Render(">>"), i18n.T("common.status.cloning"), devopsRepo)

		if !dryRun {
			if err := gitClone(ctx, defaultOrg, devopsRepo, devopsPath); err != nil {
				return fmt.Errorf("failed to clone %s: %w", devopsRepo, err)
			}
			fmt.Printf("%s %s %s\n", successStyle.Render(">>"), devopsRepo, i18n.T("cmd.setup.cloned"))
		} else {
			fmt.Printf("  %s %s/%s to %s\n", i18n.T("cmd.setup.would_clone"), defaultOrg, devopsRepo, devopsPath)
		}
	} else {
		fmt.Printf("%s %s %s\n", dimStyle.Render(">>"), devopsRepo, i18n.T("cmd.setup.already_exists"))
	}

	// Load the repos.yaml from core-devops
	registryPath := filepath.Join(devopsPath, devopsReposYaml)

	if dryRun {
		fmt.Printf("\n%s %s %s\n", dimStyle.Render(">>"), i18n.T("cmd.setup.would_load_registry"), registryPath)
		return nil
	}

	reg, err := repos.LoadRegistry(coreio.Local, registryPath)
	if err != nil {
		return fmt.Errorf("failed to load registry from %s: %w", devopsRepo, err)
	}

	// Override base path to target directory
	reg.BasePath = targetDir

	// Check workspace config for default_only if no filter specified
	if only == "" {
		if wsConfig, err := workspace.LoadConfig(devopsPath); err == nil && wsConfig != nil && len(wsConfig.DefaultOnly) > 0 {
			only = strings.Join(wsConfig.DefaultOnly, ",")
		}
	}

	// Now run the regular setup with the loaded registry
	return runRegistrySetupWithReg(ctx, reg, registryPath, only, dryRun, all, runBuild)
}

// isGitRepoRoot returns true if the directory is a git repository root.
// Handles both regular repos (.git is a directory) and worktrees (.git is a file).
func isGitRepoRoot(path string) bool {
	return coreio.Local.Exists(filepath.Join(path, ".git"))
}

// isDirEmpty returns true if the directory is empty or contains only hidden files.
func isDirEmpty(path string) (bool, error) {
	entries, err := coreio.Local.List(path)
	if err != nil {
		return false, err
	}

	for _, e := range entries {
		name := e.Name()
		// Ignore common hidden/metadata files
		if name == ".DS_Store" || name == ".git" || name == ".gitignore" {
			continue
		}
		// Any other non-hidden file means directory is not empty
		if len(name) > 0 && name[0] != '.' {
			return false, nil
		}
	}

	return true, nil
}
