package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/google/uuid"
)

type KlarnaClient struct {
	Url      string
	UserName string
	Password string
	client   *http.Client
}

func NewKlarnaClient(url, userName, password string) *KlarnaClient {
	return &KlarnaClient{
		Url:      url,
		UserName: userName,
		Password: password,
		client:   &http.Client{},
	}
}

const (
	KlarnaPlaygroundUrl = "https://api.playground.klarna.com"
)

func (k *KlarnaClient) GetOrder(orderId string) (*CheckoutOrder, error) {
	req, err := http.NewRequest("GET", k.Url+"/checkout/v3/orders/"+orderId, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")
	req.SetBasicAuth(k.UserName, k.Password)

	res, err := k.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	return k.getOrderResponse(res)
}

func (k *KlarnaClient) getOrderResponse(res *http.Response) (*CheckoutOrder, error) {
	var err error
	var klarnaOrderResponse CheckoutOrder
	if res.StatusCode >= 200 && res.StatusCode <= 299 {
		err = json.NewDecoder(res.Body).Decode(&klarnaOrderResponse)
		if err != nil {
			return nil, err
		}
		return &klarnaOrderResponse, nil
	}
	body, err := io.ReadAll(res.Body)
	if err == nil {
		log.Println(string(body))
	}

	return nil, fmt.Errorf("%s", res.Status)
}

func (k *KlarnaClient) CreateOrder(reader io.Reader) (*CheckoutOrder, error) {
	//bytes.NewReader(reply.Payload)
	req, err := http.NewRequest("POST", k.Url+"/checkout/v3/orders", reader)
	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")
	req.SetBasicAuth(k.UserName, k.Password)

	res, err := http.DefaultClient.Do(req)
	if nil != err {
		return nil, err
	}
	defer res.Body.Close()
	return k.getOrderResponse(res)
}

func (k *KlarnaClient) UpdateOrder(orderId string, reader io.Reader) (*CheckoutOrder, error) {
	//bytes.NewReader(reply.Payload)
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/checkout/v3/orders/%s", k.Url, orderId), reader)
	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")
	req.SetBasicAuth(k.UserName, k.Password)

	res, err := http.DefaultClient.Do(req)
	if nil != err {
		return nil, err
	}
	defer res.Body.Close()
	return k.getOrderResponse(res)
}

func (k *KlarnaClient) AbortOrder(orderId string) error {
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/checkout/v3/orders/%s/abort", k.Url, orderId), nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(k.UserName, k.Password)

	_, err = http.DefaultClient.Do(req)
	return err
}

// ordermanagement/v1/orders/{order_id}/acknowledge
func (k *KlarnaClient) AcknowledgeOrder(orderId string) error {
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/ordermanagement/v1/orders/%s/acknowledge", k.Url, orderId), nil)
	if err != nil {
		return err
	}
	id := uuid.New()

	req.SetBasicAuth(k.UserName, k.Password)
	req.Header.Add("Klarna-Idempotency-Key", id.String())

	_, err = http.DefaultClient.Do(req)
	return err
}
