package activitypub

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"time"

	"git.mstar.dev/mstar/goutils/sliceutils"
	"github.com/rs/zerolog/log"

	apshared "git.mstar.dev/mstar/linstrom/activitypub/shared"
	"git.mstar.dev/mstar/linstrom/config"
	"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
	webshared "git.mstar.dev/mstar/linstrom/web/shared"
)

func ImportRemoteAccount(targetName string) (string, error) {
	type InboundUserKey struct {
		Id    string `json:"id"`
		Owner string `json:"owner"`
		Pem   string `json:"publicKeyPem"`
	}
	type InboundUserMedia struct {
		Type      string `json:"type"`
		Url       string `json:"url"`
		MediaType string `json:"mediaType"`
	}
	type InboundUser struct {
		Id                string            `json:"id"`
		Type              string            `json:"type"`
		PreferredUsername string            `json:"preferredUsername"`
		Inbox             string            `json:"inbox"`
		PublicKey         *InboundUserKey   `json:"publicKey"`
		Published         *time.Time        `json:"published"`
		DisplayName       *string           `json:"name"`
		Description       *string           `json:"summary,omitempty"`
		PublicUrl         *string           `json:"url"`
		Icon              *InboundUserMedia `json:"icon,omitempty"`
		Banner            *InboundUserMedia `json:"image,omitempty"`
		Discoverable      *bool             `json:"discoverable"`
		Location          *string           `json:"vcard:Address,omitempty"`
		Birthday          *string           `json:"vcard:bday,omitempty"`
		SpeakAsCat        bool              `json:"speakAsCat"`
		IsCat             bool              `json:"isCat"`
		RestrictedFollow  *bool             `json:"manuallyApprovesFollowers"`
	}
	// Get the target user's link first
	webfinger, err := apshared.GetAccountWebfinger(targetName)
	if err != nil {
		return "", err
	}
	selfLinks := sliceutils.Filter(webfinger.Links, func(t apshared.LinkData) bool {
		return t.Relation == "self"
	})
	if len(selfLinks) == 0 {
		return "", errors.New("No self link")
	}
	APLink := selfLinks[0]
	req, err := http.NewRequest("GET", *APLink.Href, nil)
	if err != nil {
		return "", err
	}
	req.Header.Add("Accept", "application/activity+json")

	// Server actor key for signing
	linstromActor, err := dbgen.User.Where(dbgen.User.Username.Eq("linstrom")).First()
	if err != nil {
		return "", err
	}
	var keyBytes []byte
	if config.GlobalConfig.Experimental.UseEd25519Keys {
		keyBytes = linstromActor.PrivateKeyEd
	} else {
		keyBytes = linstromActor.PrivateKeyRsa
	}

	// Sign and send
	err = webshared.SignRequest(req, linstromActor.ID+"#main-key", keyBytes, nil)
	if err != nil {
		return "", err
	}
	response, err := webshared.RequestClient.Do(req)
	if err != nil {
		return "", err
	}
	defer response.Body.Close()
	if response.StatusCode != 200 {
		return "", errors.New("Bad status")
	}
	var data InboundUser
	body, _ := io.ReadAll(response.Body)
	log.Info().Bytes("body", body).Msg("Body from request")
	err = json.Unmarshal(body, &data)
	if err != nil {
		return "", err
	}
	log.Info().Any("received-data", data).Msg("Response data")
	return "", nil
}
