// Webhook trigger → resolve session_id (optional artifact download).
//
// Documented at https://appcd-dev.github.io/stackgen-sdk/code-samples/webhook-session-artifact/
//
//	export WEBHOOK_TOKEN='sg_aios_…'
//	go run ./examples/go/webhook/webhook-wait-session.go \
//	  -base-url https://app.stackgen.com \
//	  -api-token stackgen_… \
//	  -workspace-id <workspace-uuid> \
//	  -json-body \
//	  -query 'P1 | checkout-api error rate above SLO'
//
// -retry-max controls how many times the underlying HTTP client retries
// transient failures (network errors, 429, 5xx) with exponential backoff.
package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	stackgen "github.com/appcd-dev/stackgen-sdk/clients/go"
	"github.com/hashicorp/go-retryablehttp"
)

func envOr(keys ...string) string {
	for _, key := range keys {
		if v := strings.TrimSpace(os.Getenv(key)); v != "" {
			return v
		}
	}
	return ""
}

func text(m map[string]any, keys ...string) string {
	for _, key := range keys {
		if v, ok := m[key]; ok {
			if s, ok := v.(string); ok && strings.TrimSpace(s) != "" {
				return strings.TrimSpace(s)
			}
		}
	}
	return ""
}

func main() {
	baseURL := flag.String("base-url", envOr("STACKGEN_URL", "STACKGEN_BASE_URL"), "Mothership URL")
	apiToken := flag.String("api-token", envOr("STACKGEN_TOKEN", "STACKGEN_API_TOKEN"), "API token")
	orgID := flag.String("workspace-id", envOr("STACKGEN_WORKSPACE_ID", "STACKGEN_PROJECT", "STACKGEN_PROJECT_ID", "STACKGEN_ORG_ID", "ORG_ID"), "Workspace UUID (sent as orgId)")
	flag.StringVar(orgID, "org-id", *orgID, "Deprecated: use -workspace-id")
	webhookToken := flag.String("webhook-token", "", "Or set WEBHOOK_TOKEN")
	query := flag.String("query", "Test webhook from stackgen-sdk example", "Alert text")
	jsonBody := flag.Bool("json-body", false, "Send {\"message\",\"query\"} JSON instead of plain text")
	downloadReport := flag.Bool("download-report", false, "Also download the session artifact")
	artifactName := flag.String("artifact-name", "session-report.md", "Artifact filename")
	outputPath := flag.String("output-path", "session-report.md", "Local output path")
	timeoutSeconds := flag.Int("timeout-seconds", 1800, "Overall timeout")
	pollIntervalSeconds := flag.Int("poll-interval-seconds", 5, "Poll interval")
	retryMax := flag.Int("retry-max", 4, "Max HTTP retries with exponential backoff for transient failures")
	flag.Parse()

	wh := strings.TrimSpace(*webhookToken)
	if wh == "" {
		wh = envOr("STACKGEN_WEBHOOK_TOKEN", "WEBHOOK_TOKEN")
	}
	if strings.TrimSpace(*baseURL) == "" || strings.TrimSpace(*apiToken) == "" || strings.TrimSpace(*orgID) == "" {
		fmt.Fprintln(os.Stderr, "error: set -base-url/-api-token/-workspace-id or STACKGEN_URL/STACKGEN_TOKEN/STACKGEN_WORKSPACE_ID")
		os.Exit(2)
	}
	if wh == "" {
		fmt.Fprintln(os.Stderr, "error: set -webhook-token or WEBHOOK_TOKEN")
		os.Exit(2)
	}

	rc := retryablehttp.NewClient()
	rc.RetryMax = *retryMax
	rc.Logger = nil
	httpClient := rc.StandardClient()

	client, err := stackgen.NewClient(stackgen.Config{
		BaseURL:             *baseURL,
		APIToken:            *apiToken,
		WebhookToken:        wh,
		WorkspaceID:         *orgID,
		ArtifactName:        *artifactName,
		OutputPath:          *outputPath,
		TimeoutSeconds:      *timeoutSeconds,
		PollIntervalSeconds: *pollIntervalSeconds,
		HTTPClient:          httpClient,
	})
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	payload := *query
	if *jsonBody {
		raw, _ := json.Marshal(map[string]string{"message": *query, "query": *query})
		payload = string(raw)
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(*timeoutSeconds)*time.Second)
	defer cancel()

	trigger, err := client.Aiden.TriggerWebhook(ctx, payload)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	enc := json.NewEncoder(os.Stdout)
	enc.SetIndent("", "  ")
	_ = enc.Encode(trigger)

	sessionID := text(trigger, "session_id", "sessionId")
	webhookID := text(trigger, "webhook_id", "webhookId")
	invocationID := text(trigger, "invocation_id", "invocationId")
	dispatchRunID := text(trigger, "run_id", "runId", "id")
	if sessionID == "" {
		if webhookID == "" || invocationID == "" {
			fmt.Fprintln(os.Stderr, "trigger response missing session_id and run ids")
			os.Exit(1)
		}
		sessionID, err = client.Aiden.WaitForWebhookSession(ctx, webhookID, invocationID, dispatchRunID, nil)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}
	fmt.Fprintf(os.Stderr, "session_id=%s\n", sessionID)

	if *downloadReport {
		if _, err := client.Aiden.WaitForSessionArtifact(ctx, sessionID, *artifactName); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		path, err := client.Aiden.DownloadSessionArtifact(ctx, sessionID, *artifactName, *outputPath)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		if _, err := os.Stat(path); err != nil {
			fmt.Fprintf(os.Stderr, "download missing file %s: %v\n", path, err)
			os.Exit(1)
		}
		fmt.Fprintf(os.Stderr, "downloaded %s\n", path)
	}
}
