package main

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

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

	switch args[0] {
	case "init":
		cmdProjectInit(args[1:])
	case "list":
		cmdProjectList()
	case "show":
		cmdProjectShow(args[1:])
	case "status":
		cmdProjectStatus(args[1:])
	case "help", "-h", "--help":
		printProjectUsage()
	default:
		fmt.Fprintf(os.Stderr, "unknown project subcommand: %s\n", args[0])
		printProjectUsage()
		os.Exit(1)
	}
}

func printProjectUsage() {
	fmt.Println(`fn project — manage project workspaces

Usage:
  fn project init <nombre>       Crea scaffold de proyecto
  fn project list                Lista proyectos del registry
  fn project show <id>           Muestra proyecto con apps, analysis y vaults
  fn project status [<id>]       Estado resumido de un proyecto`)
}

func cmdProjectInit(args []string) {
	if len(args) < 1 {
		fmt.Fprintln(os.Stderr, "usage: fn project init <nombre>")
		os.Exit(1)
	}
	name := args[0]
	r := root()
	projDir := filepath.Join(r, "projects", name)

	if _, err := os.Stat(projDir); err == nil {
		fmt.Fprintf(os.Stderr, "project %q already exists at %s\n", name, projDir)
		os.Exit(1)
	}

	// Create directory structure
	dirs := []string{
		projDir,
		filepath.Join(projDir, "apps"),
		filepath.Join(projDir, "analysis"),
		filepath.Join(projDir, "vaults"),
	}
	for _, d := range dirs {
		if err := os.MkdirAll(d, 0o755); err != nil {
			fmt.Fprintf(os.Stderr, "error creating %s: %v\n", d, err)
			os.Exit(1)
		}
	}

	// Create project.md
	projectMD := fmt.Sprintf(`---
name: %s
description: ""
tags: []
repo_url: ""
---

## Notas

`, name)
	if err := os.WriteFile(filepath.Join(projDir, "project.md"), []byte(projectMD), 0o644); err != nil {
		fmt.Fprintf(os.Stderr, "error writing project.md: %v\n", err)
		os.Exit(1)
	}

	// Create vault.yaml
	vaultYAML := `vaults: []
`
	if err := os.WriteFile(filepath.Join(projDir, "vaults", "vault.yaml"), []byte(vaultYAML), 0o644); err != nil {
		fmt.Fprintf(os.Stderr, "error writing vault.yaml: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Project %q created at %s\n", name, projDir)
	fmt.Println("\nStructure:")
	fmt.Printf("  %s/\n", filepath.Join("projects", name))
	fmt.Printf("    project.md\n")
	fmt.Printf("    apps/\n")
	fmt.Printf("    analysis/\n")
	fmt.Printf("    vaults/\n")
	fmt.Printf("      vault.yaml\n")
	fmt.Println("\nNext steps:")
	fmt.Printf("  1. Edit projects/%s/project.md (add description and tags)\n", name)
	fmt.Printf("  2. Create apps or analysis inside the project\n")
	fmt.Printf("  3. Run 'fn index' to register the project\n")
}

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

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

	if len(projects) == 0 {
		fmt.Println("No projects found. Create one with 'fn project init <nombre>'.")
		return
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "ID\tDESCRIPTION\tTAGS")
	for _, p := range projects {
		desc := truncate(p.Description, 50)
		tags := strings.Join(p.Tags, ", ")
		fmt.Fprintf(w, "%s\t%s\t%s\n", p.ID, desc, tags)
	}
	w.Flush()
}

func cmdProjectShow(args []string) {
	if len(args) < 1 {
		fmt.Fprintln(os.Stderr, "usage: fn project show <id>")
		os.Exit(1)
	}
	id := args[0]

	db := openDB()
	defer db.Close()

	p, err := db.GetProject(id)
	if err != nil {
		fmt.Fprintf(os.Stderr, "project not found: %s\n", id)
		os.Exit(1)
	}

	fmt.Printf("ID:          %s\n", p.ID)
	fmt.Printf("Name:        %s\n", p.Name)
	fmt.Printf("Description: %s\n", p.Description)
	fmt.Printf("Tags:        %s\n", strings.Join(p.Tags, ", "))
	fmt.Printf("Dir:         %s\n", p.DirPath)
	if p.RepoURL != "" {
		fmt.Printf("Repo URL:    %s\n", p.RepoURL)
	}
	if p.Notes != "" {
		fmt.Printf("\nNotes:\n%s\n", p.Notes)
	}
	if p.Documentation != "" {
		fmt.Printf("\nDocumentation:\n%s\n", p.Documentation)
	}

	// Show project apps
	apps, _ := db.GetProjectApps(id)
	if len(apps) > 0 {
		fmt.Printf("\nApps (%d):\n", len(apps))
		for _, a := range apps {
			fmt.Printf("  - %s (%s) — %s\n", a.ID, a.Lang, truncate(a.Description, 60))
		}
	}

	// Show project analysis
	analyses, _ := db.GetProjectAnalysis(id)
	if len(analyses) > 0 {
		fmt.Printf("\nAnalysis (%d):\n", len(analyses))
		for _, an := range analyses {
			fmt.Printf("  - %s (%s) — %s\n", an.ID, an.Lang, truncate(an.Description, 60))
		}
	}

	// Show project vaults
	vaults, _ := db.GetProjectVaults(id)
	if len(vaults) > 0 {
		fmt.Printf("\nVaults (%d):\n", len(vaults))
		for _, v := range vaults {
			sym := ""
			if v.Symlink {
				sym = fmt.Sprintf(" -> %s", v.Path)
			}
			fmt.Printf("  - %s — %s%s\n", v.Name, v.Description, sym)
		}
	}
}

func cmdProjectStatus(args []string) {
	db := openDB()
	defer db.Close()

	if len(args) > 0 {
		// Status for a specific project
		id := args[0]
		p, err := db.GetProject(id)
		if err != nil {
			fmt.Fprintf(os.Stderr, "project not found: %s\n", id)
			os.Exit(1)
		}

		apps, _ := db.GetProjectApps(id)
		analyses, _ := db.GetProjectAnalysis(id)
		vaults, _ := db.GetProjectVaults(id)

		fmt.Printf("%s — %s\n", p.Name, p.Description)
		fmt.Printf("  Apps:     %d\n", len(apps))
		fmt.Printf("  Analysis: %d\n", len(analyses))
		fmt.Printf("  Vaults:   %d\n", len(vaults))
		fmt.Printf("  Updated:  %s\n", p.UpdatedAt.Format("2006-01-02 15:04"))
		return
	}

	// Status for all projects
	projects, err := db.ListAllProjects()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	if len(projects) == 0 {
		fmt.Println("No projects found.")
		return
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "PROJECT\tAPPS\tANALYSIS\tVAULTS\tUPDATED")
	for _, p := range projects {
		apps, _ := db.GetProjectApps(p.ID)
		analyses, _ := db.GetProjectAnalysis(p.ID)
		vaults, _ := db.GetProjectVaults(p.ID)
		fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s\n",
			p.Name, len(apps), len(analyses), len(vaults),
			p.UpdatedAt.Format("2006-01-02"))
	}
	w.Flush()
}
