package sample

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/go-redis/redis/v8"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"google.golang.org/grpc"

	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
)

func RedisHandler(w http.ResponseWriter, r *http.Request) {
	rdb := redis.NewClient(&redis.Options{})
	rdb.Ping(r.Context())
	rdb.Get(r.Context(), "key1")
	rdb.Get(r.Context(), "key2")
	rdb.Get(r.Context(), "key3")
	payload, _ := json.Marshal(map[string]any{"name": "big"})
	rdb.Set(r.Context(), "profile", payload, time.Hour)
	rdb.Set(r.Context(), "cache", "val", 0)
	rdb.Keys(r.Context(), "*")
	_ = w
}

func GRPCHandler(w http.ResponseWriter, r *http.Request) {
	conn, _ := grpc.Dial("localhost:50051")
	_ = conn
	_ = w
}

func LogHandler(w http.ResponseWriter, r *http.Request) {
	logger, _ := zap.NewProduction()
	logger.Info(fmt.Sprintf("user %s logged in", "test"))
	log.Printf("request received: %s", r.URL.Path)
	key := viper.GetString("api_key")
	apiKey := os.Getenv("API_KEY")
	err := fmt.Errorf("oops")
	logger.Error("failed", zap.Error(err))
	_ = key
	_ = apiKey
	_ = w
	_ = err
}

func DebugLog() {
	logger, _ := zap.NewProduction()
	logger.Sugar().Debugf("data: %v", computeDebug())
}

func ErrorLogAndReturn(err error) error {
	logger, _ := zap.NewProduction()
	logger.Error("something failed", zap.Error(err))
	return err
}

func computeDebug() string { return "debug" }

func PromHandler(w http.ResponseWriter, r *http.Request) {
	counter := prometheus.NewCounter(prometheus.CounterOpts{Name: "req"})
	counter.WithLabelValues(r.URL.Path)
	_ = w
}

func UnregisteredMetric() {
	gauge := prometheus.NewGauge(prometheus.GaugeOpts{Name: "temp"})
	gauge.Set(42)
}

func AWSHandler(w http.ResponseWriter, r *http.Request) {
	sess, _ := session.NewSession()
	_ = sess
	_ = w
}

func HardcodedAWSCreds() {
	_ = credentials.NewStaticCredentials("AKID123", "secret123", "")
}

func CobraRun(cmd *cobra.Command) {
	val, _ := cmd.Flags().GetString("output")
	_ = val
}

func ReadConfigPerReq(w http.ResponseWriter, r *http.Request) {
	viper.ReadInConfig()
	_ = w
}

type ListRequest struct{}

type ListItem struct {
	Name string
}

type ListResponse struct {
	Items []ListItem
}

func GRPCLargeUnary(ctx context.Context, req *ListRequest) (*ListResponse, error) {
	items := make([]ListItem, 0, 20000)
	return &ListResponse{Items: items}, nil
}

func GRPCContextDrop(ctx context.Context, req *ListRequest) (*ListResponse, error) {
	child := context.Background()
	_ = child
	return &ListResponse{}, nil
}

func GRPCServer() {
	_ = grpc.NewServer()
}

func GRPCInterceptorPerRPC(ctx context.Context, req *ListRequest) error {
	_ = grpc.UnaryInterceptor(nil)
	return nil
}

func EnvParsingInit() {
	_, _ = strconv.Atoi(os.Getenv("PORT"))
	_, _ = strconv.Atoi(os.Getenv("LIMIT"))
	_, _ = strconv.Atoi(os.Getenv("WORKERS"))
	_, _ = strconv.Atoi(os.Getenv("RETRIES"))
}

func PromObserve(w http.ResponseWriter, r *http.Request) {
	start := time.Now()
	hist := prometheus.NewHistogram(prometheus.HistogramOpts{Name: "latency"})
	hist.Observe(time.Since(start).Seconds())
	_ = w
	_ = r
}

func S3PartialRead(w http.ResponseWriter, r *http.Request) {
	sess, _ := session.NewSession()
	obj, _ := s3.New(sess).GetObject(&s3.GetObjectInput{})
	io.LimitReader(obj.Body, 1024)
	_ = w
	_ = r
}

func S3ListHandler(w http.ResponseWriter, r *http.Request) {
	sess, _ := session.NewSession()
	s3.New(sess).ListObjectsV2(&s3.ListObjectsV2Input{})
	_ = w
	_ = r
}

func DynamoScanHandler(w http.ResponseWriter, r *http.Request) {
	sess, _ := session.NewSession()
	dynamodb.New(sess).Scan(&dynamodb.ScanInput{})
	_ = w
	_ = r
}
