package main

import (
	"errors"
	"fmt"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/golang/protobuf/proto"
	"github.com/urfave/cli"

	"code.justin.tv/dta/rockpaperscissors/client/metric"
)

func init() {
	var client *metric.Client
	cmd := cli.Command{
		Name:  "metrics",
		Usage: "commands related to the metrics service",
		Before: func(c *cli.Context) error {
			var err error
			client, err = metric.NewClient(c.GlobalString("rps-addr"))
			if err != nil {
				return err
			}
			return nil
		},
		After: func(c *cli.Context) error {
			if client == nil {
				return nil
			}
			if err := client.Close(); err != nil {
				log.Error(err)
			}
			return nil
		},
		Subcommands: []cli.Command{
			{
				Name:  "list",
				Usage: "list all known metrics",
				Action: func(c *cli.Context) error {
					return printMetricList(client)
				},
			},
			{
				Name:      "info",
				Usage:     "get information about a particular metric",
				ArgsUsage: "ID",
				Action: func(c *cli.Context) error {
					id := c.Args().Get(0)
					if len(id) == 0 {
						return errors.New("metric ID argument is required")
					}
					return printMetricInfo(client, id)
				},
			},
			{
				Name:      "get",
				Usage:     "get the timeseries for a particular metric",
				ArgsUsage: "ID",
				Flags: []cli.Flag{
					cli.DurationFlag{
						Name:  "period",
						Usage: "how far back to query for",
						Value: 7 * 24 * time.Hour,
					},
					cli.StringFlag{
						Name:  "bucket-size",
						Usage: "how granular to make the time series (day, week, month, quarter, year)",
						Value: "day",
					},
					cli.StringFlag{
						Name:  "project",
						Usage: "select metrics for a project",
					},
					cli.StringFlag{
						Name:  "developer",
						Usage: "select metrics for a developer",
					},
					cli.StringFlag{
						Name:  "team",
						Usage: "select metrics for a team",
					},
					cli.StringFlag{
						Name:  "org",
						Usage: "select metrics for a organization",
					},
				},
				Action: func(c *cli.Context) error {
					id := c.Args().Get(0)
					if len(id) == 0 {
						return errors.New("metric ID argument is required")
					}
					bucketSize, err := metric.BucketSizeString(
						strings.ToUpper(c.String("bucket-size")))
					if err != nil {
						return err
					}

					selector := metric.SelectorOpt{
						ProjectID: c.String("project"),
						Developer: c.String("developer"),
						Team:      c.String("team"),
						Org:       c.String("org"),
					}

					return printMetric(client, id, c.Duration("period"), bucketSize, selector)
				},
			},
		},
	}
	app.Commands = append(app.Commands, cmd)
}

func printMetricList(client *metric.Client) error {
	metrics, err := client.ListMetrics()
	if err != nil {
		return err
	}
	for _, metric := range metrics {
		if metric.GetKeyMetric() {
			fmt.Printf("%s: %s (key metric)\n", metric.MetricId, metric.Description)
		} else {
			fmt.Printf("%s: %s\n", metric.MetricId, metric.Description)
		}
	}
	return nil
}

func printMetricInfo(client *metric.Client, id string) error {
	metric, err := client.GetMetricInfo(id)
	if err != nil {
		return err
	}
	fmt.Print(proto.MarshalTextString(metric))
	return nil
}

func printMetric(client *metric.Client, id string, period time.Duration, bucketSize metric.BucketSize, selector metric.SelectorOpt) error {
	end := time.Now()
	start := end.Add(-period)
	metric, err := client.GetMetric(id, start, end, bucketSize, selector)
	if err != nil {
		return err
	}
	fmt.Print(proto.MarshalTextString(metric))
	return nil
}
