package cmd

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/spf13/cobra"

	"omixlab.com/mosis-portal/pkg/mospkg"
)

// InitCmd returns the init command
func InitCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "init [directory]",
		Short: "Create a new Mosis app project",
		Long: `Create a new Mosis app project with boilerplate files.

If directory is not specified, the current directory is used.
If the directory contains files, you will be prompted to confirm.`,
		Args: cobra.MaximumNArgs(1),
		RunE: runInit,
	}

	cmd.Flags().String("name", "", "App name")
	cmd.Flags().String("id", "", "Package ID (e.g., com.yourname.app)")
	cmd.Flags().String("description", "", "App description")
	cmd.Flags().String("author", "", "Author name")
	cmd.Flags().String("email", "", "Author email")
	cmd.Flags().Bool("yes", false, "Skip confirmation prompts")

	return cmd
}

func runInit(cmd *cobra.Command, args []string) error {
	// Determine target directory
	dir := "."
	if len(args) > 0 {
		dir = args[0]
	}

	// Create directory if needed
	if dir != "." {
		if err := os.MkdirAll(dir, 0755); err != nil {
			return fmt.Errorf("create directory: %w", err)
		}
	}

	// Check if directory has files
	entries, _ := os.ReadDir(dir)
	skip, _ := cmd.Flags().GetBool("yes")
	if len(entries) > 0 && !skip {
		fmt.Printf("Directory %s is not empty. Continue? [y/N] ", dir)
		reader := bufio.NewReader(os.Stdin)
		answer, _ := reader.ReadString('\n')
		if strings.ToLower(strings.TrimSpace(answer)) != "y" {
			fmt.Println("Aborted.")
			return nil
		}
	}

	// Gather project info
	info, err := gatherProjectInfo(cmd)
	if err != nil {
		return err
	}

	fmt.Println("\nCreating project structure...")

	// Create manifest.json
	manifest := mospkg.Manifest{
		ID:              info.id,
		Name:            info.name,
		Version:         "1.0.0",
		VersionCode:     1,
		Entry:           "assets/main.rml",
		MinMosisVersion: "1.0.0",
		Description:     info.description,
		Author: &mospkg.Author{
			Name:  info.author,
			Email: info.email,
		},
		Permissions: []string{},
		Icons: mospkg.Icons{
			Size32:  "icons/icon-32.png",
			Size64:  "icons/icon-64.png",
			Size128: "icons/icon-128.png",
		},
		Orientation:     "portrait",
		BackgroundColor: "#FFFFFF",
	}

	manifestJSON, _ := json.MarshalIndent(manifest, "", "  ")
	if err := writeFile(dir, "manifest.json", manifestJSON); err != nil {
		return err
	}
	fmt.Println("✓ Created manifest.json")

	// Create main.rml
	mainRML := fmt.Sprintf(`<rml>
<head>
    <title>%s</title>
    <link type="text/rcss" href="styles/theme.rcss"/>
    <script src="scripts/app.lua"></script>
</head>
<body>
    <div class="container">
        <h1>%s</h1>
        <p>%s</p>
    </div>
</body>
</rml>
`, info.name, info.name, info.description)
	if err := writeFile(dir, "assets/main.rml", []byte(mainRML)); err != nil {
		return err
	}
	fmt.Println("✓ Created assets/main.rml")

	// Create theme.rcss
	themeRCSS := `/* Theme styles for the app */

body {
    font-family: LatoLatin;
    font-size: 16dp;
    color: #333333;
    background-color: #FFFFFF;
}

.container {
    padding: 16dp;
}

h1 {
    font-size: 24dp;
    font-weight: bold;
    margin-bottom: 8dp;
}

p {
    line-height: 1.5;
}
`
	if err := writeFile(dir, "assets/styles/theme.rcss", []byte(themeRCSS)); err != nil {
		return err
	}
	fmt.Println("✓ Created assets/styles/theme.rcss")

	// Create app.lua
	appLua := `-- App initialization script

function onLoad()
    print("App loaded: ` + info.name + `")
end

function onUnload()
    print("App unloaded")
end
`
	if err := writeFile(dir, "assets/scripts/app.lua", []byte(appLua)); err != nil {
		return err
	}
	fmt.Println("✓ Created assets/scripts/app.lua")

	// Create placeholder icon files
	if err := createPlaceholderIcons(dir); err != nil {
		return err
	}
	fmt.Println("✓ Created icons/ (placeholder icons)")

	// Create .mosisignore
	mosisignore := `# Files to exclude from package
.git/
.gitignore
*.md
dist/
.mosisignore
`
	if err := writeFile(dir, ".mosisignore", []byte(mosisignore)); err != nil {
		return err
	}
	fmt.Println("✓ Created .mosisignore")

	// Print next steps
	projectDir := info.dirName
	if dir == "." {
		projectDir = "."
	}

	fmt.Printf(`
Project created! Next steps:
`)
	if projectDir != "." {
		fmt.Printf("  cd %s\n", projectDir)
	}
	fmt.Println("  mosis run          # Preview in designer")
	fmt.Println("  mosis build        # Create package")
	fmt.Println("  mosis publish      # Submit to store")

	return nil
}

type projectInfo struct {
	name        string
	id          string
	description string
	author      string
	email       string
	dirName     string
}

func gatherProjectInfo(cmd *cobra.Command) (*projectInfo, error) {
	reader := bufio.NewReader(os.Stdin)
	info := &projectInfo{}

	// Get from flags or prompt
	name, _ := cmd.Flags().GetString("name")
	if name == "" {
		fmt.Print("? App name: ")
		name, _ = reader.ReadString('\n')
		name = strings.TrimSpace(name)
	}
	if name == "" {
		return nil, fmt.Errorf("app name is required")
	}
	info.name = name

	id, _ := cmd.Flags().GetString("id")
	if id == "" {
		fmt.Print("? Package ID (e.g., com.yourname.app): ")
		id, _ = reader.ReadString('\n')
		id = strings.TrimSpace(id)
	}
	if id == "" || !isValidPackageID(id) {
		return nil, fmt.Errorf("valid package ID is required (e.g., com.yourname.app)")
	}
	info.id = id

	description, _ := cmd.Flags().GetString("description")
	if description == "" {
		fmt.Print("? Description: ")
		description, _ = reader.ReadString('\n')
		description = strings.TrimSpace(description)
	}
	info.description = description

	author, _ := cmd.Flags().GetString("author")
	if author == "" {
		fmt.Print("? Author name: ")
		author, _ = reader.ReadString('\n')
		author = strings.TrimSpace(author)
	}
	info.author = author

	email, _ := cmd.Flags().GetString("email")
	if email == "" {
		fmt.Print("? Author email: ")
		email, _ = reader.ReadString('\n')
		email = strings.TrimSpace(email)
	}
	info.email = email

	// Generate directory name from app name
	info.dirName = strings.ToLower(strings.ReplaceAll(info.name, " ", "-"))
	info.dirName = regexp.MustCompile(`[^a-z0-9-]`).ReplaceAllString(info.dirName, "")

	return info, nil
}

var packageIDPattern = regexp.MustCompile(`^[a-z][a-z0-9]*(\.[a-z][a-z0-9_]*)+$`)

func isValidPackageID(id string) bool {
	return packageIDPattern.MatchString(id)
}

func writeFile(dir, relPath string, content []byte) error {
	fullPath := filepath.Join(dir, relPath)
	if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
		return fmt.Errorf("create directory for %s: %w", relPath, err)
	}
	return os.WriteFile(fullPath, content, 0644)
}

func createPlaceholderIcons(dir string) error {
	// Create minimal PNG placeholders (1x1 white pixel)
	// In a real implementation, you'd generate proper placeholder icons
	minimalPNG := []byte{
		0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG signature
		0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR chunk
		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
		0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53,
		0xDE, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41,
		0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0xFF,
		0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59,
		0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E,
		0x44, 0xAE, 0x42, 0x60, 0x82, // IEND chunk
	}

	sizes := []int{32, 64, 128}
	for _, size := range sizes {
		path := fmt.Sprintf("icons/icon-%d.png", size)
		if err := writeFile(dir, path, minimalPNG); err != nil {
			return err
		}
	}

	return nil
}
