package servicecatalog

import (
	"bytes"
	"context"
	"encoding/json"
	"io/ioutil"
	"net/http"

	"code.justin.tv/eventbus/controlplane/internal/environment"

	"github.com/pkg/errors"
)

const (
	stagingEndpoint    = "https://us-west-2.beta.goracle.s.twitch.a2z.com/api/v2/query"
	productionEndpoint = "https://us-west-2.prod.goracle.s.twitch.a2z.com/api/v2/query"
)

type Service struct {
	ID           string       `json:"id"`
	Name         string       `json:"name"`
	Description  string       `json:"description"`
	Pagerduty    string       `json:"pagerduty"`
	SlackChannel SlackChannel `json:"slack_channel"`
}

type Response struct {
	Name        string
	Description string
	Slack       string
	Pagerduty   string
}

type SlackChannel struct {
	Name string
}

type ServiceCatalogResponse struct {
	Data ServiceCatalogResponseData `json:"data"`
}

type ServiceCatalogResponseData struct {
	Services []Service `json:"services"`
}

type Fetcher interface {
	fetchServices(ctx context.Context) ([]Service, error)
}

type ServiceCatalogFetcher struct {
	httpClient *http.Client
}

func (f *ServiceCatalogFetcher) fetchServices(ctx context.Context) ([]Service, error) {
	env := environment.Environment()
	var endpoint string
	if environment.IsStagingEnv(env) {
		endpoint = stagingEndpoint
	} else if environment.IsProductionEnv(env) {
		endpoint = productionEndpoint
	} else {
		return nil, errors.Errorf("attempted to fetch services for invalid environment %s", env)
	}

	query := "{ \"query\": \"query { services() { id name description pagerduty slack_channel { name } } }\" }"
	req, err := http.NewRequest("POST", endpoint, bytes.NewBufferString(query))
	if err != nil {
		return nil, errors.Wrap(err, "could not create request to service catalog")
	}
	req.Header.Set("Content-Type", "application/json")
	req = req.WithContext(ctx)

	resp, err := f.httpClient.Do(req)
	if err != nil {
		return nil, errors.Wrap(err, "could not perform request to service catalog")
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, errors.Errorf("recieved %d from service catalog", resp.StatusCode)
	}

	respBodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, errors.Wrap(err, "could not read response body")
	}

	var response ServiceCatalogResponse
	err = json.Unmarshal(respBodyBytes, &response)
	if err != nil {
		return nil, errors.Wrap(err, "could not unmarshal service catalog response")
	}

	return response.Data.Services, nil
}
