package main

import (
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"
)

// registerCommonIssueFlags registers flags common to create and update commands.
func registerCommonIssueFlags(cmd *cobra.Command) {
	cmd.Flags().StringP("assignee", "a", "", "Assignee")
	cmd.Flags().StringP("description", "d", "", "Issue description")
	cmd.Flags().String("body", "", "Alias for --description (GitHub CLI convention)")
	_ = cmd.Flags().MarkHidden("body") // Hidden alias for agent/CLI ergonomics
	cmd.Flags().String("body-file", "", "Read description from file (use - for stdin)")
	cmd.Flags().String("description-file", "", "Alias for --body-file")
	_ = cmd.Flags().MarkHidden("description-file") // Hidden alias
	cmd.Flags().String("design", "", "Design notes")
	cmd.Flags().String("acceptance", "", "Acceptance criteria")
	cmd.Flags().String("external-ref", "", "External reference (e.g., 'gh-9', 'jira-ABC')")
}

// getDescriptionFlag retrieves the description value, checking --body-file, --description-file,
// --description, and --body (in that order of precedence).
// Supports reading from stdin via --description=- or --body=- (useful when description
// contains apostrophes or other characters that are hard to escape in shell).
// Returns the value and whether any flag was explicitly changed.
func getDescriptionFlag(cmd *cobra.Command) (string, bool) {
	bodyFileChanged := cmd.Flags().Changed("body-file")
	descFileChanged := cmd.Flags().Changed("description-file")
	descChanged := cmd.Flags().Changed("description")
	bodyChanged := cmd.Flags().Changed("body")

	// Check for conflicting file flags
	if bodyFileChanged && descFileChanged {
		bodyFile, _ := cmd.Flags().GetString("body-file")
		descFile, _ := cmd.Flags().GetString("description-file")
		if bodyFile != descFile {
			fmt.Fprintf(os.Stderr, "Error: cannot specify both --body-file and --description-file with different values\n")
			os.Exit(1)
		}
	}

	// File flags take precedence over string flags
	if bodyFileChanged || descFileChanged {
		var filePath string
		if bodyFileChanged {
			filePath, _ = cmd.Flags().GetString("body-file")
		} else {
			filePath, _ = cmd.Flags().GetString("description-file")
		}

		// Error if both file and string flags are specified
		if descChanged || bodyChanged {
			fmt.Fprintf(os.Stderr, "Error: cannot specify both --body-file and --description/--body\n")
			os.Exit(1)
		}

		content, err := readBodyFile(filePath)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error reading body file: %v\n", err)
			os.Exit(1)
		}
		return content, true
	}

	// Check if description or body is "-" (read from stdin)
	// This provides a convenient shorthand: --description=- instead of --body-file=-
	desc, _ := cmd.Flags().GetString("description")
	body, _ := cmd.Flags().GetString("body")

	if desc == "-" || body == "-" {
		// Error if both are set to different values
		if descChanged && bodyChanged && desc != body {
			fmt.Fprintf(os.Stderr, "Error: cannot specify both --description and --body with different values\n")
			fmt.Fprintf(os.Stderr, "  --description: %q\n", desc)
			fmt.Fprintf(os.Stderr, "  --body:        %q\n", body)
			os.Exit(1)
		}
		content, err := readBodyFile("-")
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error reading from stdin: %v\n", err)
			os.Exit(1)
		}
		return content, true
	}

	// Error if both description and body are specified with different values
	if descChanged && bodyChanged {
		if desc != body {
			fmt.Fprintf(os.Stderr, "Error: cannot specify both --description and --body with different values\n")
			fmt.Fprintf(os.Stderr, "  --description: %q\n", desc)
			fmt.Fprintf(os.Stderr, "  --body:        %q\n", body)
			os.Exit(1)
		}
	}

	// Return whichever was set (or description's value if neither)
	if bodyChanged {
		return body, true
	}

	return desc, descChanged
}

// readBodyFile reads the description content from a file.
// If filePath is "-", reads from stdin.
func readBodyFile(filePath string) (string, error) {
	var reader io.Reader

	if filePath == "-" {
		reader = os.Stdin
	} else {
		// #nosec G304 - filePath comes from user flag, validated by caller
		file, err := os.Open(filePath)
		if err != nil {
			return "", fmt.Errorf("failed to open file: %w", err)
		}
		defer file.Close()
		reader = file
	}

	content, err := io.ReadAll(reader)
	if err != nil {
		return "", fmt.Errorf("failed to read file: %w", err)
	}

	return string(content), nil
}

// registerPriorityFlag registers the priority flag with a specific default value.
func registerPriorityFlag(cmd *cobra.Command, defaultVal string) {
	cmd.Flags().StringP("priority", "p", defaultVal, "Priority (0-4 or P0-P4, 0=highest)")
}
