package main

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

	"github.com/spf13/cobra"
)

func main() {
	cmd := newRootCmd()
	cmd.SetArgs(normalizeArgs(os.Args[1:]))
	cobra.CheckErr(cmd.Execute())
}

func newRootCmd() *cobra.Command {
	var destination string
	var packageName string
	var verbose bool

	cmd := &cobra.Command{
		Use:   "dummygen [interface]",
		Short: "Generate dummy implementation for a Go interface",
		Args:  cobra.MinimumNArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			packageArg := args[0]
			interfaceNames, err := parseInterfaceNames(args[1:])
			if err != nil {
				return err
			}
			cwd, err := os.Getwd()
			if err != nil {
				return err
			}
			logVerbose(verbose, "dummygen: cwd=%s\n", cwd)
			logVerbose(verbose, "dummygen: package=%s interfaces=%s\n", packageArg, strings.Join(interfaceNames, ", "))
			logVerbose(verbose, "dummygen: destination=%s output_package=%s\n", destination, packageName)

			pkgInfo, err := LoadPackageFromImport(packageArg, cwd)
			if err != nil {
				return err
			}
			logVerbose(verbose, "dummygen: loaded package %s (%s)\n", pkgInfo.Package.Name(), pkgInfo.Package.Path())

			interfaces := make([]InterfaceSpec, 0, len(interfaceNames))
			for _, name := range interfaceNames {
				iface, err := FindInterface(pkgInfo, name)
				if err != nil {
					return err
				}
				interfaces = append(interfaces, InterfaceSpec{
					Name:      name,
					Interface: iface,
				})
			}

			if packageName == "" {
				packageName = pkgInfo.Package.Name()
			}

			gen := NewGenerator(GeneratorOptions{
				PackageName: packageName,
				Interfaces:  interfaces,
				PackageInfo: pkgInfo,
			})

			content, err := gen.Generate()
			if err != nil {
				return err
			}
			logVerbose(verbose, "dummygen: generated bytes=%d\n", len(content))

			if err := os.MkdirAll(filepath.Dir(destination), 0o755); err != nil {
				return err
			}
			logVerbose(verbose, "dummygen: wrote file %s\n", destination)

			return os.WriteFile(destination, content, 0o600)
		},
	}

	cmd.Flags().StringVarP(&destination, "destination", "d", "", "output file path")
	cmd.Flags().StringVarP(&packageName, "package", "p", "", "package name of generated file")
	cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "enable verbose logging")
	cobra.CheckErr(cmd.MarkFlagRequired("destination"))

	return cmd
}

func logVerbose(enabled bool, format string, args ...any) {
	if !enabled {
		return
	}
	fmt.Fprintf(os.Stderr, format, args...)
}

func parseInterfaceNames(args []string) ([]string, error) {
	var names []string
	for _, arg := range args {
		parts := strings.Split(arg, ",")
		for _, part := range parts {
			name := strings.TrimSpace(part)
			if name == "" {
				continue
			}
			names = append(names, name)
		}
	}
	if len(names) == 0 {
		return nil, fmt.Errorf("interface name is required")
	}
	return names, nil
}

func normalizeArgs(args []string) []string {
	if len(args) == 0 {
		return args
	}
	normalized := make([]string, 0, len(args))
	for i := 0; i < len(args); i++ {
		arg := args[i]
		switch {
		case strings.HasPrefix(arg, "-package="):
			normalized = append(normalized, "--"+strings.TrimPrefix(arg, "-"))
		case arg == "-package":
			normalized = append(normalized, "--package")
		case strings.HasPrefix(arg, "-destination="):
			normalized = append(normalized, "--"+strings.TrimPrefix(arg, "-"))
		case arg == "-destination":
			normalized = append(normalized, "--destination")
		case arg == "-verbose":
			normalized = append(normalized, "--verbose")
		default:
			normalized = append(normalized, arg)
		}
	}
	return normalized
}
