package validation

import (
	"context"
	"strconv"

	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/sqs"

	"github.com/pkg/errors"

	"code.justin.tv/eventbus/controlplane/internal/db"
	"code.justin.tv/eventbus/controlplane/internal/validator"
)

// this is the underlying aws error code when an assume role fails for
// permission issues.
const errCodeAccessDenied = "AccessDenied"

var ErrEventStreamMissingTopic = errors.New("event stream sns topic does not exist")
var ErrEventStreamMissingS3Route = errors.New("event stream s3 route does not exist")
var ErrEventStreamInvalidS3Route = errors.New("event stream s3 routing information invalid")

type SubscriptionTarget struct {
	*db.SubscriptionTarget
	qv *validator.QueueValidator
}

func (e *SubscriptionTarget) ID() string {
	return itemID(e)
}

func (e *SubscriptionTarget) Type() string {
	return "SubscriptionTarget"
}

func (e *SubscriptionTarget) Attributes() []*ItemAttribute {
	return []*ItemAttribute{
		{
			Key:   "Name",
			Value: e.Name,
		},
		{
			Key:   "ARN",
			Value: e.SQSDetails.SQSQueueARN,
		},
		{
			Key:   "ServiceID",
			Value: strconv.Itoa(e.ServiceID),
		},
	}
}

func (e *SubscriptionTarget) Validate(ctx context.Context) (*Report, error) {
	err := e.qv.ValidateQueue(ctx, e.SQSDetails.SQSQueueURL)
	if err != nil {
		if aerr, ok := errors.Cause(err).(awserr.Error); ok {
			switch aerr.Code() {
			case sqs.ErrCodeQueueDoesNotExist, errCodeAccessDenied:
				return Warn(e, err.Error()), nil
			default:
				return nil, errors.Wrap(err, "could not validate subscription target")
			}
		}
		cause := errors.Cause(err)
		for _, validationError := range validator.AllQueueErrors {
			if cause == validationError {
				return Warn(e, cause.Error()), nil
			}
		}
		return nil, errors.Wrap(err, "could not validate subscription target")
	}

	return Ok(e), nil
}

func SubscriptionTargets(ctx context.Context, db db.DB, sqsManager validator.SQSManager, eventbusAWSAccountID, encryptionAtRestKeyARN string) ([]Item, error) {

	qv := validator.NewQueueValidator(sqsManager, eventbusAWSAccountID, encryptionAtRestKeyARN)

	subscriptionsTargets, err := db.SubscriptionTargets(ctx)
	if err != nil {
		return nil, errors.Wrap(err, "could not get subscription targets")
	}

	items := make([]Item, 0)
	for _, target := range subscriptionsTargets {
		items = append(items, &SubscriptionTarget{
			SubscriptionTarget: target,
			qv:                 qv,
		})
	}

	return items, nil
}
