package main

import (
	"flag"
	"io"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"code.justin.tv/common/chitin"
	_ "code.justin.tv/common/golibs/bininfo"
	"code.justin.tv/release/trace/api"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

var (
	serverHostPort = flag.String("server", "trace-api.prod.us-west2.justin.tv:11143", "The server hostport")
	service        = flag.String("svc", "code.justin.tv/video/birdcage", "The service to analyze")
	sampling       = flag.Float64("sample", 0.1, "Sampling rate")
	duration       = flag.Duration("t", time.Second, "How long to capture data")
	status         = flag.Int("status", 503, "HTTP status to search for")
)

func main() {
	flag.Parse()

	err := chitin.ExperimentalTraceProcessOptIn()
	if err != nil {
		log.Fatalf("trace enable err=%q", err)
	}

	conn, err := grpc.Dial(*serverHostPort, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("dial err=%q", err)
	}
	defer conn.Close()
	client := api.NewTraceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), *duration)

	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, syscall.SIGINT)
	go func() {
		<-sigch
		cancel()
	}()

	firehose, err := client.Firehose(ctx, &api.FirehoseRequest{
		Sampling: *sampling,
		Query: &api.Query{
			Comparisons: []*api.Comparison{
				&api.Comparison{
					ServiceName:    &api.StringComparison{Value: *service},
					HttpStatusCode: &api.IntegerComparison{Value: int64(*status), Type: api.IntegerComparison_EQUALS},
				},
			},
		},
	})
	if err != nil {
		log.Fatalf("firehose err=%q", err)
	}

	result := consumeFirehose(firehose)
	if _, err := result.WriteTo(os.Stdout); err != nil {
		log.Fatalf("dump err=%q", err)
	}
}

type data struct{}

func consumeFirehose(firehose api.Trace_FirehoseClient) io.WriterTo {
	var tx *api.Transaction
	var err error

	d := &data{}

	for tx, err = firehose.Recv(); err == nil; tx, err = firehose.Recv() {
		var search func(*api.Call)
		search = func(call *api.Call) {
			if svc := call.GetSvc(); svc != nil && svc.Name == *service {
				if h := call.GetParams().GetHttp(); h != nil && h.Status == int32(*status) {
					log.Printf("status=%d duration=%s", h.Status, api.ServiceDuration(call))
				}
			}
			for _, sub := range call.Subcalls {
				search(sub)
			}
		}
		search(tx.Root)
	}

	if err != nil {
		switch grpc.Code(err) {
		case codes.DeadlineExceeded:
		default:
		}
	}
	return d
}

func (d *data) WriteTo(w io.Writer) (int64, error) {
	var nn int64

	return nn, nil
}
