package client

import (
	"bytes"
	"context"
	"crypto"
	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/rsa"
	"fmt"
	"net/http"
	"net/url"
	"reflect"

	"github.com/common-fate/httpsig"
	"github.com/common-fate/httpsig/alg_ecdsa"
	"github.com/common-fate/httpsig/alg_ed25519"
	"github.com/common-fate/httpsig/alg_rsa"
	"github.com/common-fate/httpsig/signer"
)

func Post(baseUrl *url.URL, key crypto.PrivateKey, keyId string, data []byte) (*http.Response, error) {
	client, err := getSigningClient(key, keyId)

	if err != nil {
		return nil, err
	}

	var req *http.Request

	req, err = http.NewRequest("POST", baseUrl.String(), bytes.NewBuffer(data))

	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")

	resp, err := client.Do(req)

	return resp, err
}

func getSigningClient(key crypto.PrivateKey, keyId string) (*http.Client, error) {
	var alg signer.Algorithm

	switch p := key.(type) {
	case *rsa.PrivateKey:
		alg = alg_rsa.NewRSAPKCS256Signer(p)
	case *ed25519.PrivateKey:
		alg = alg_ed25519.Ed25519{PrivateKey: *p}
	case *ecdsa.PrivateKey:
		alg = alg_ecdsa.NewP256Signer(p)
	default:
		return nil, fmt.Errorf("type is unknown: %s", reflect.TypeOf(key))
	}

	coveredComponents := []string{"@method", "@target-uri", "content-type", "content-length"}

	client := httpsig.NewClient(httpsig.ClientOpts{
		Tag:               "auth",
		KeyID:             keyId,
		Alg:               alg,
		CoveredComponents: coveredComponents,

		OnDeriveSigningString: func(ctx context.Context, stringToSign string) {
			fmt.Printf("string to sign:\n%s\n", stringToSign)
		},
	})

	return client, nil
}