// Copyright 2020 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package webstack_test

import (
	"log"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/maruel/panicparse/v2/stack/webstack"
)

func ExampleSnapshotHandler() {
	http.HandleFunc("/debug/panicparse", webstack.SnapshotHandler)

	// Access as http://localhost:6060/debug/panicparse
	log.Println(http.ListenAndServe("localhost:6060", nil))
}

func ExampleSnapshotHandler_complex() {
	// This example does a few things:
	// - Diables "augment" by default, can be enabled manually with "?augment=1".
	// - Forces the "maxmem" value to reduce memory pressure in worst case.
	// - Serializes handler to one at a time.
	// - Throttles requests to once per second.
	// - Limit request source IP to localhost and 100.64.x.x/10. (e.g.
	//   Tailscale).

	const delay = time.Second
	mu := sync.Mutex{}
	var last time.Time
	http.HandleFunc("/debug/panicparse", func(w http.ResponseWriter, req *http.Request) {
		// Only allow requests from localhost or in the 100.64.x.x/10 IPv4 range.
		ok := false
		if i := strings.LastIndexByte(req.RemoteAddr, ':'); i != -1 {
			switch ip := req.RemoteAddr[:i]; ip {
			case "localhost", "127.0.0.1", "[::1]", "::1":
				ok = true
			default:
				p := net.ParseIP(ip).To4()
				ok = p != nil && p[0] == 100 && p[1] >= 64 && p[1] < 128
			}
		}
		if !ok {
			http.Error(w, "forbidden", http.StatusForbidden)
			return
		}

		// Serialize the handler.
		mu.Lock()
		defer mu.Unlock()

		// Throttle requests.
		if time.Since(last) < delay {
			http.Error(w, "retry later", http.StatusTooManyRequests)
			return
		}

		// Must be called before touching req.Form.
		req.ParseForm()
		// Disables source scanning by default since it's heavy.
		if req.FormValue("augment") == "" {
			req.Form.Set("augment", "0")
		}
		// Reduces maximum memory usage to 32MiB (from 64MiB) for the goroutines
		// snapshot.
		req.Form.Set("maxmem", "33554432")

		webstack.SnapshotHandler(w, req)
		last = time.Now()
	})

	// Access as http://localhost:6060/debug/panicparse
	log.Println(http.ListenAndServe("localhost:6060", nil))
}
