package cmd

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"

	"github.com/spf13/cobra"
	"github.com/tidbcloud/clinic-cli/internal/clinic"
)

func eventsCommandHandler(ctx *RuntimeContext, args []string, stdout io.Writer) error {
	command := newEventsCommand(staticRuntime(ctx), stdout)
	if err := executeCobraCommand(command, args); err != nil {
		return normalizeFamilyCommandError(err, "events")
	}
	return nil
}

func newEventsCommand(runtime runtimeResolver, stdout io.Writer) *cobra.Command {
	command := newCommand(commandMetadata{
		Use:   "events",
		Short: "List activity events for a cluster.",
		Long:  "List cluster activity events.",
	}, stdout)
	command.RunE = func(c *cobra.Command, _ []string) error {
		return c.Help()
	}
	command.Args = cobra.NoArgs
	command.AddCommand(
		newEventsListCommand(runtime, stdout),
	)
	return command
}

type eventsListOptions struct {
	clusterID   string
	rangeStart  string
	rangeEnd    string
	name        string
	severity    int
	limit       int
	cursor      string
	severitySet bool
	limitSet    bool
}

func newEventsListCommand(runtime runtimeResolver, stdout io.Writer) *cobra.Command {
	var opts eventsListOptions
	command := newCommand(commandMetadata{
		Use:   "list",
		Short: "List activities for a cluster and time range.",
		Long: `List activity events for a cluster.

Behavior:
  --cluster-id can be provided by flag, CLINIC_CLUSTER_ID, or selected profile defaults.
  --start and --end can be provided by flags, CLINIC_RANGE_START/CLINIC_RANGE_END,
  or selected profile defaults. If both are unresolved, defaults to --start now-7d and --end now.
  --limit must be greater than 0 when provided.

Time formats:
  --start/--end accept now and now-<duration> (for example now-30m, now-3h30m, now-1d),
  datetime (for example "2026-04-02 14:29:09", timezone optional, defaults to local),
  or epoch in s/ms/ns.`,
	}, stdout)
	command.Args = cobra.NoArgs
	command.Flags().StringVar(&opts.clusterID, "cluster-id", "", "Cluster ID.")
	command.Flags().StringVar(&opts.rangeStart, "start", "", "Activity range start timestamp (datetime or epoch s/ms/ns).")
	command.Flags().StringVar(&opts.rangeEnd, "end", "", "Activity range end timestamp (datetime or epoch s/ms/ns).")
	command.Flags().StringVar(&opts.name, "name", "", "Activity name filter.")
	command.Flags().IntVar(&opts.severity, "severity", 0, "Activity severity filter.")
	command.Flags().IntVar(&opts.limit, "limit", 0, "Maximum number of activities.")
	command.Flags().StringVar(&opts.cursor, "cursor", "", "Pagination cursor header value.")
	command.RunE = func(c *cobra.Command, _ []string) error {
		ctx, err := runtime()
		if err != nil {
			return err
		}
		opts.severitySet = c.Flags().Changed("severity")
		opts.limitSet = c.Flags().Changed("limit")
		return runEventsList(ctx, opts, stdout)
	}
	return command
}

func runEventsList(ctx *RuntimeContext, opts eventsListOptions, stdout io.Writer) error {
	resolvedClusterID, err := requiredFlagOrEnvWithContext(ctx, "cluster-id", opts.clusterID, envClinicClusterID)
	if err != nil {
		return err
	}
	resolvedStart, resolvedEnd, err := resolveRequiredRangeWithFallback(ctx, "start", opts.rangeStart, "end", opts.rangeEnd, defaultEventsRangeFallbackWindow)
	if err != nil {
		return err
	}

	clusterRef, err := resolveClusterReferenceByID(ctx, resolvedClusterID)
	if err != nil {
		return err
	}

	params := url.Values{}
	startUnix, err := parseTimeFlagToUnixSeconds("start", resolvedStart)
	if err != nil {
		return err
	}
	endUnix, err := parseTimeFlagToUnixSeconds("end", resolvedEnd)
	if err != nil {
		return err
	}
	params.Set("begin_ts", startUnix)
	params.Set("end_ts", endUnix)
	addOptionalString(params, "name", opts.name)
	if opts.severitySet {
		params.Set("severity", strconv.Itoa(opts.severity))
	}
	if opts.limitSet {
		if opts.limit <= 0 {
			return errors.New("limit must be greater than 0")
		}
		params.Set("limit", strconv.Itoa(opts.limit))
	}

	headers := http.Header{}
	if opts.cursor != "" {
		headers.Set("Cursor", opts.cursor)
	}

	return executeClinicJSON(ctx, clinic.Request{
		Method:  http.MethodGet,
		Path:    fmt.Sprintf("/clinic/api/v1/activityhub/applications/%s/targets/%s/activities", clusterRef.OrgID, clusterRef.ClusterID),
		Query:   params,
		Headers: headers,
	}, stdout)
}
