package main

import (
	"fmt"
	"go/format"
	"os"
	"path/filepath"

	"github.com/keepmind9/acp-sdk-go/internal/schemagen"
	"github.com/spf13/cobra"
)

func genAllCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "all",
		Short: "Generate all schema files (schema + meta)",
		RunE:  runGenAll,
	}
	cmd.Flags().StringVarP(&flagInput, "input", "i", "./schema", "Input directory (contains schema.json and meta.json)")
	cmd.Flags().StringVarP(&flagOutput, "output", "o", "./schema", "Output directory")
	cmd.Flags().BoolVar(&flagDryRun, "dry-run", false, "Print to stdout instead of writing files")
	return cmd
}

func runGenAll(cmd *cobra.Command, args []string) error {
	// hardcoded paths so sibling subcommand flags can't poison the values
	const schemaPath = "./schema/schema.json"
	const metaPath = "./schema/meta.json"
	const outputDir = "./schema"

	if err := runGenSchema(schemaPath, outputDir, flagDryRun); err != nil {
		return fmt.Errorf("gen schema: %w", err)
	}
	if err := runGenMeta(metaPath, outputDir, flagDryRun); err != nil {
		return fmt.Errorf("gen meta: %w", err)
	}
	return nil
}

func genSchemaCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "schema",
		Short: "Generate Go types from schema.json",
		RunE:  runGenSchemaCmd,
	}
	cmd.Flags().StringVarP(&flagInput, "input", "i", "./schema/schema.json", "Input schema.json path")
	cmd.Flags().StringVarP(&flagOutput, "output", "o", "./schema", "Output directory")
	cmd.Flags().BoolVar(&flagDryRun, "dry-run", false, "Print to stdout instead of writing files")
	return cmd
}

func runGenSchemaCmd(cmd *cobra.Command, args []string) error {
	return runGenSchema("./schema/schema.json", "./schema", flagDryRun)
}

func genMetaCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "meta",
		Short: "Generate meta constants from meta.json",
		RunE:  runGenMetaCmd,
	}
	cmd.Flags().StringVarP(&flagInput, "input", "i", "./schema/meta.json", "Input meta.json path")
	cmd.Flags().StringVarP(&flagOutput, "output", "o", "./schema", "Output directory")
	cmd.Flags().BoolVar(&flagDryRun, "dry-run", false, "Print to stdout instead of writing files")
	return cmd
}

func runGenMetaCmd(cmd *cobra.Command, args []string) error {
	inputPath, _ := cmd.Flags().GetString("input")
	outputDir, _ := cmd.Flags().GetString("output")
	return runGenMeta(inputPath, outputDir, flagDryRun)
}

func runGenSchema(schemaPath, outputDir string, dryRun bool) error {
	s, err := schemagen.Load(schemaPath)
	if err != nil {
		return fmt.Errorf("load schema: %w", err)
	}

	gen := schemagen.NewGenerator(s)
	files := gen.GenerateAll()

	if dryRun {
		for name, content := range files {
			fmt.Printf("=== %s ===\n%s\n", name, content)
		}
		return nil
	}

	for filename, rawContent := range files {
		formatted, err := format.Source([]byte(rawContent))
		if err != nil {
			// If formatting fails (should not happen), write raw content
			formatted = []byte(rawContent)
		}
		outPath := filepath.Join(outputDir, filename)
		if err := os.WriteFile(outPath, formatted, 0644); err != nil {
			return fmt.Errorf("write %s: %w", filename, err)
		}
		fmt.Printf("Generated %s\n", filename)
	}
	return nil
}

func runGenMeta(metaPath, outputDir string, dryRun bool) error {
	return GenerateMeta(metaPath, outputDir, dryRun)
}
