package seed

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"

	"code.justin.tv/eventbus/controlplane/e2e/internal/resource"
)

// Contains minimal representations of various EventBus data models
// in slim JSON representation for easy seeding of databases for E2E test runs

const (
	servicesSeedData            = "./e2e/internal/seed/data/%s/services.json"
	eventDefinitionsSeedData    = "./e2e/internal/seed/data/%s/event_definitions.json"
	publicationsSeedData        = "./e2e/internal/seed/data/%s/publications.json"
	subscriptionTargetsSeedData = "./e2e/internal/seed/data/%s/subscription_targets.json"
	subscriptionsSeedData       = "./e2e/internal/seed/data/%s/subscriptions.json"
	featureFlagSeedData         = "./e2e/internal/seed/data/%s/feature_flags.json"
)

type Data struct {
	Services            []*resource.Service
	EventDefinitions    []*resource.EventDefinition
	Publications        []*resource.Publication
	SubscriptionTargets []*resource.SubscriptionTarget
	Subscriptions       []*resource.Subscription
	FeatureFlags        []*resource.FeatureFlag
}

// Fetch happens.
// Returns seed data
func Fetch(testName string) (*Data, error) {
	var err error
	var b []byte

	servicesPath := fmt.Sprintf(servicesSeedData, testName)
	eventDefinitionsPath := fmt.Sprintf(eventDefinitionsSeedData, testName)
	publicationsPath := fmt.Sprintf(publicationsSeedData, testName)
	subscriptionTargetsPath := fmt.Sprintf(subscriptionTargetsSeedData, testName)
	subscriptionsPath := fmt.Sprintf(subscriptionsSeedData, testName)
	featureFlagsPath := fmt.Sprintf(featureFlagSeedData, testName)

	eventDefinitions := make([]*resource.EventDefinition, 0)
	if fileExists(eventDefinitionsPath) {
		if b, err = ioutil.ReadFile(eventDefinitionsPath); err != nil {
			return nil, err
		}
		if err = json.Unmarshal(b, &eventDefinitions); err != nil {
			return nil, err
		}
	}

	services := make([]*resource.Service, 0)
	if fileExists(servicesPath) {
		if b, err = ioutil.ReadFile(servicesPath); err != nil {
			return nil, err
		}
		if err = json.Unmarshal(b, &services); err != nil {
			return nil, err
		}
	}

	publications := make([]*resource.Publication, 0)
	if fileExists(publicationsPath) {
		if b, err = ioutil.ReadFile(publicationsPath); err != nil {
			return nil, err
		}
		if err = json.Unmarshal(b, &publications); err != nil {
			return nil, err
		}
	}

	subscriptionTargets := make([]*resource.SubscriptionTarget, 0)
	if fileExists(subscriptionTargetsPath) {
		if b, err = ioutil.ReadFile(subscriptionTargetsPath); err != nil {
			return nil, err
		}
		if err = json.Unmarshal(b, &subscriptionTargets); err != nil {
			return nil, err
		}
	}

	subscriptions := make([]*resource.Subscription, 0)
	if fileExists(subscriptionsPath) {
		if b, err = ioutil.ReadFile(subscriptionsPath); err != nil {
			return nil, err
		}
		if err = json.Unmarshal(b, &subscriptions); err != nil {
			return nil, err
		}
	}

	featureFlags := make([]*resource.FeatureFlag, 0)
	if fileExists(featureFlagsPath) {
		if b, err = ioutil.ReadFile(featureFlagsPath); err != nil {
			return nil, err
		}
		if err = json.Unmarshal(b, &featureFlags); err != nil {
			return nil, err
		}
	}

	return &Data{
		Services:            services,
		EventDefinitions:    eventDefinitions,
		Publications:        publications,
		SubscriptionTargets: subscriptionTargets,
		Subscriptions:       subscriptions,
		FeatureFlags:        featureFlags,
	}, nil
}

// checks if a file exists and panics if there is an error checking
func fileExists(path string) bool {
	if _, err := os.Stat(path); err != nil {
		// path/to/whatever does not exist
		if os.IsNotExist(err) {
			return false
		}
		panic(err)
	}
	return true
}
