package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	log "github.com/sirupsen/logrus"
	"golang.org/x/oauth2"
	"mortons.site/tps/internal/properties"
)

type Config struct {
	Hostname string
	Username string
	Password string
	ClientID string
}

// Authenticate using OAuth2 password credentials
func GetAccessToken(c *Config) (string, error) {

	// Setup OAuth2 authentication.
	conf := oauth2.Config{
		ClientID:     c.ClientID,
		ClientSecret: "",
		Endpoint: oauth2.Endpoint{
			TokenURL: "https://" + c.Hostname + "/oidc-token-service/" + c.ClientID + "/token",
		},
		Scopes: []string{"oidc", "tags", "context_entitlements", "content_entitlements", "em_api_access"},
	}
	log.WithFields(log.Fields{"conf": fmt.Sprintf("%+v", conf)}).Debug()
	token, err := conf.PasswordCredentialsToken(oauth2.NoContext, c.Username, c.Password)
	if err != nil {
		log.Error("Error retrieving AccessToken. Chech configuration, username and password")
		return "", err
	}
	log.WithFields(log.Fields{"token": fmt.Sprintf("%+v", token.AccessToken)}).Debug()
	return token.AccessToken, nil
}

func GetProperties(c *Config, q string) (string, error) {
	accessToken, err := GetAccessToken(c)

	if err != nil {
		log.Error(err)
		return "", err
	}

	url := "https://" + c.Hostname + "/tenant-properties-service/" + c.ClientID + "/properties?fields=name,value,lastModifiedDate,lastModifiedBy"

	if len(q) > 0 {
		url += "&q=" + q
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Error(err)
		return "", err
	}
	req.Header.Add("Authorization", "OIDC_id_token "+accessToken)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Error(err)
		return "", err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Error(err)
		return "", err
	}

	return string(body), nil
}

func UpdateProperty(c *Config, p []properties.PropertyUpdateOrCreate) error {
	accessToken, err := GetAccessToken(c)

	if err != nil {
		return err
	}
	url := "https://" + c.Hostname + "/tenant-properties-service/" + c.ClientID + "/properties"

	body, err := json.Marshal(p)
	if err != nil {
		log.Error(err)
		return err
	}

	req, err := http.NewRequest("PATCH", url, bytes.NewBuffer(body))
	if err != nil {
		log.Error(err)
		return err
	}
	req.Header.Add("Authorization", "OIDC_id_token "+accessToken)
	req.Header.Add("Content-Type", "application/ld+json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Error(err)
		return err
	}
	defer res.Body.Close()
	response, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Error(err)
		return err
	}

	log.Debug(string(response))

	rp := []properties.PropertyUpdateOrCreate{}

	json.Unmarshal(response, &rp)
	if strings.HasPrefix("2", res.Status) {
		log.Error(rp[0].Status + rp[0].Description)
	}

	return nil
}

func DeleteProperty(c *Config, p []properties.PropertyDelete) error {
	accessToken, err := GetAccessToken(c)

	if err != nil {
		return err
	}
	url := "https://" + c.Hostname + "/tenant-properties-service/" + c.ClientID + "/properties"

	body, err := json.Marshal(p)
	if err != nil {
		log.Error(err)
		return err
	}

	req, err := http.NewRequest("PATCH", url, bytes.NewBuffer(body))
	if err != nil {
		log.Error(err)
		return err
	}
	req.Header.Add("Authorization", "OIDC_id_token "+accessToken)
	req.Header.Add("Content-Type", "application/ld+json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Error(err)
		return err
	}
	defer res.Body.Close()
	response, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Error(err)
		return err
	}

	log.Debug(string(response))

	rp := []properties.PropertyDelete{}

	json.Unmarshal(response, &rp)
	if strings.HasPrefix("2", res.Status) {
		log.Error(rp[0].Status + rp[0].Description)
	}

	return nil
}
