package historycmd

import (
	"context"
	"encoding/csv"
	"errors"
	"flag"
	"net/http"
	"os"
	"strconv"

	"code.justin.tv/foundation/history-admin/internal/awssig"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/google/subcommands"
	elastic "gopkg.in/olivere/elastic.v5"
)

// HistCmd ...
type HistCmd struct {
	*BaseCmd

	elastic    *elastic.Client
	actionType string
}

// Name implements subcommands
func (cmd HistCmd) Name() string {
	return "hist"
}

// Synopsis implements subcommands
func (cmd HistCmd) Synopsis() string {
	return "get hist for an action type"
}

// Usage implements subcommands
func (cmd HistCmd) Usage() string {
	return `hist -action [action-type] > out.csv
`
}

// SetFlags implements subcommands
func (cmd *HistCmd) SetFlags(f *flag.FlagSet) {
	f.StringVar(&cmd.actionType, "action", "", "action to get histogram for.")
}

// Execute implements subcommands
func (cmd HistCmd) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
	if err := cmd.init(ctx); err != nil {
		cmd.Logger.Error(err)
		return subcommands.ExitFailure
	}

	if err := cmd.execute(ctx); err != nil {
		cmd.Logger.Error(err)
		return subcommands.ExitFailure
	}

	return subcommands.ExitSuccess
}

func (cmd HistCmd) execute(ctx context.Context) error {
	result, err := cmd.elastic.
		Search().
		Index("history-*").
		Type("audits").
		Query(elastic.NewBoolQuery().
			Filter(elastic.NewTermsQuery("action", cmd.actionType))).
		Aggregation("created_at_buckets", elastic.NewDateHistogramAggregation().
			Field("created_at").
			Interval("day")).
		Do(ctx)
	if err != nil {
		return err
	}

	hist, ok := result.Aggregations.DateHistogram("created_at_buckets")
	if !ok {
		return errors.New("could not get buckets")
	}

	w := csv.NewWriter(os.Stdout)
	defer func() {
		w.Flush()
	}()

	if err := w.Write([]string{
		"date",
		"hard_delete_count",
	}); err != nil {
		return err
	}

	for _, bucket := range hist.Buckets {
		if err := w.Write([]string{
			*bucket.KeyAsString,
			strconv.FormatInt(bucket.DocCount, 10),
		}); err != nil {
			return err
		}
	}
	return nil
}

func (cmd *HistCmd) init(ctx context.Context) error {
	if cmd.actionType == "" {
		return errors.New("action type is required")
	}

	elasticSearchClient, err := cmd.elasticSearchClient()
	if err != nil {
		return err
	}
	cmd.elastic = elasticSearchClient
	return nil
}

// ConfigureClient configures the elasticsearch client with a chain of role arns
func (cmd HistCmd) elasticSearchClient() (*elastic.Client, error) {
	elasticSearchRoleArn, err := cmd.ElasticSearchRoleArn()
	if err != nil {
		return nil, err
	}

	elasticSearchURL, err := cmd.ElasticSearchURL()
	if err != nil {
		return nil, err
	}

	return elastic.NewSimpleClient(
		elastic.SetURL(elasticSearchURL),
		elastic.SetHttpClient(&http.Client{
			Transport: &awssig.RoundTripper{
				AWSService: "es",
				Credentials: stscreds.NewCredentials(session.Must(session.NewSession(&aws.Config{
					Region:      aws.String("us-west-2"),
					Credentials: nil,
				})), elasticSearchRoleArn),
			},
		}),
	)
}
