package historycmd

import (
	"fmt"
	"net/http"
	"sync"

	"code.justin.tv/foundation/history-admin/clients/audit"
	"code.justin.tv/foundation/history-admin/internal/awssig"
	"code.justin.tv/foundation/history.v2/historyin"
	"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/sirupsen/logrus"
	elastic "gopkg.in/olivere/elastic.v5"
)

// BaseCmd is the base struct all admin cmds use
type BaseCmd struct {
	Environment string
	Logger      logrus.FieldLogger

	initSync  sync.Once
	audit     *audit.Client
	historyin *historyin.Client
}

func (cmd *BaseCmd) init() {
	cmd.initSync.Do(func() {
		cmd.Logger.Infof("using environment: %s", cmd.Environment)

		cmd.audit = &audit.Client{
			Environment:   cmd.Environment,
			Logger:        cmd.Logger,
			ScanBatchSize: 10000,
		}

		cmd.historyin = &historyin.Client{
			Environment:    cmd.Environment,
			FlushBatchSize: 500,
			Logger:         &logger{cmd.Logger},
		}
	})
}

// Audit returns the audit client
func (cmd *BaseCmd) Audit() *audit.Client {
	cmd.init()
	return cmd.audit
}

// HistoryIn returns the history ingest client
func (cmd *BaseCmd) HistoryIn() *historyin.Client {
	cmd.init()
	return cmd.historyin
}

// ElasticSearchURL returns the elasticsearch url
func (cmd *BaseCmd) ElasticSearchURL() (string, error) {
	cmd.init()

	switch cmd.Environment {
	case "staging":
		return "https://search-history-v2-staging-ndcrtqghpmqkgafmeunhocpjoy.us-west-2.es.amazonaws.com", nil
	case "prod":
		return "https://search-history-v2-prod-f3x3silxwhxrbtxbhtovmd5ozq.us-west-2.es.amazonaws.com", nil
	}

	return "", fmt.Errorf("invalid environment: %s", cmd.Environment)
}

// ElasticSearchRoleArn returns the elasticsearch role arn
func (cmd *BaseCmd) ElasticSearchRoleArn() (string, error) {
	cmd.init()

	switch cmd.Environment {
	case "staging":
		return "arn:aws:iam::005087123760:role/history-v2-staging-read", nil
	case "prod":
		return "arn:aws:iam::958416494912:role/history-v2-prod-read", nil
	}

	return "", fmt.Errorf("invalid environment: %s", cmd.Environment)
}

func (cmd *BaseCmd) logExecutionCount(action string, every int) func() {
	var (
		nCount int
		lock   sync.Mutex
	)

	return func() {
		lock.Lock()
		nCount++
		if (nCount % every) == 0 {
			cmd.Logger.Infof("%s: %d", action, nCount)
		}
		lock.Unlock()
	}
}

// ConfigureClient configures the elasticsearch client with a chain of role arns
func (cmd *BaseCmd) 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),
			},
		}),
	)
}
