package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/tabwriter"
)

func cmdApp(args []string) {
	if len(args) < 1 {
		printAppUsage()
		os.Exit(1)
	}

	switch args[0] {
	case "list":
		appList()
	case "clone":
		if len(args) < 2 {
			fmt.Fprintln(os.Stderr, "usage: fn app clone <id>")
			os.Exit(1)
		}
		appClone(args[1])
	case "pull":
		if len(args) < 2 {
			fmt.Fprintln(os.Stderr, "usage: fn app pull <id>")
			os.Exit(1)
		}
		appPull(args[1])
	case "help", "-h":
		printAppUsage()
	default:
		fmt.Fprintf(os.Stderr, "unknown app command: %s\n", args[0])
		printAppUsage()
		os.Exit(1)
	}
}

func printAppUsage() {
	fmt.Println(`fn app — manage registry apps

Usage:
  fn app list              List all apps (local + remote)
  fn app clone <id>        Clone app repo to apps/<name>/
  fn app pull <id>         Git pull in existing clone`)
}

func appList() {
	db := openDB()
	defer db.Close()

	apps, err := db.ListAllApps()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	if len(apps) == 0 {
		fmt.Println("No apps registered.")
		return
	}

	r := root()
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "ID\tLANG\tDOMAIN\tSTATUS\tREPO_URL")
	for _, a := range apps {
		status := "local"
		if a.RepoURL != "" {
			dirPath := filepath.Join(r, "apps", a.Name)
			if _, err := os.Stat(dirPath); os.IsNotExist(err) {
				status = "remote"
			} else {
				status = "cloned"
			}
		}
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", a.ID, a.Lang, a.Domain, status, a.RepoURL)
	}
	w.Flush()
}

func appClone(id string) {
	db := openDB()
	defer db.Close()

	a, err := db.GetApp(id)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	if a.RepoURL == "" {
		fmt.Fprintf(os.Stderr, "app %s has no repo_url set\n", id)
		os.Exit(1)
	}

	r := root()
	target := filepath.Join(r, "apps", a.Name)
	if _, err := os.Stat(target); err == nil {
		fmt.Fprintf(os.Stderr, "directory already exists: %s\n", target)
		os.Exit(1)
	}

	fmt.Printf("Cloning %s → %s\n", a.RepoURL, target)
	cmd := exec.Command("git", "clone", a.RepoURL, target)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "git clone failed: %v\n", err)
		os.Exit(1)
	}
	fmt.Println("Done. Run 'fn index' to re-index.")
}

func appPull(id string) {
	db := openDB()
	defer db.Close()

	a, err := db.GetApp(id)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	r := root()
	dir := filepath.Join(r, "apps", a.Name)
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "app not cloned locally: %s\n", dir)
		fmt.Fprintln(os.Stderr, "Run 'fn app clone "+id+"' first.")
		os.Exit(1)
	}

	fmt.Printf("Pulling %s\n", dir)
	cmd := exec.Command("git", "-C", dir, "pull")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "git pull failed: %v\n", err)
		os.Exit(1)
	}
	fmt.Println("Done. Run 'fn index' to re-index.")
}

// formatRepoURL ensures the URL does not contain inline credentials for display.
func formatRepoURL(url string) string {
	if strings.Contains(url, "@") && strings.Contains(url, "://") {
		// Mask credentials in URLs like https://user:pass@host/...
		parts := strings.SplitN(url, "://", 2)
		if len(parts) == 2 {
			atIdx := strings.LastIndex(parts[1], "@")
			if atIdx >= 0 {
				return parts[0] + "://" + parts[1][atIdx+1:]
			}
		}
	}
	return url
}
