package client

import (
	"context"
	_ "embed"
	"encoding/json"
	"github.com/google/uuid"
	"github.com/loveuer/nf"
	"github.com/loveuer/nf/nft/log"
	"github.com/loveuer/nf/nft/resp"
	"golang.org/x/oauth2"
	"net/http"
	"uauth/internal/tool"
)

//go:embed login.html
var page string

var (
	config = oauth2.Config{
		ClientID:     "test",
		ClientSecret: "Foobar123",
		Endpoint: oauth2.Endpoint{
			AuthURL:  "http://localhost:8080/oauth/v2/authorize",
			TokenURL: "http://localhost:8080/oauth/v2/token",
		},
		RedirectURL: "http://localhost:18080/oauth/v2/redirect",
		Scopes:      []string{"test"},
	}
	state = uuid.New().String()[:8]
)

func Run(ctx context.Context) error {
	app := nf.New()
	app.Get("/login", handleLogin)
	app.Get("/oauth/v2/redirect", handleRedirect)

	go func() {
		<-ctx.Done()
		_ = app.Shutdown(tool.Timeout(2))
	}()

	return app.Run(":18080")
}

func handleLogin(c *nf.Ctx) error {
	if c.Query("oauth") != "" {
		uri := config.AuthCodeURL(state)
		log.Info("[C] oauth config client_secret = %s", config.ClientSecret)
		log.Info("[C] redirect to oauth2 server uri = %s", uri)
		return c.Redirect(uri, http.StatusFound)
	}

	return c.HTML(page)
}

func handleRedirect(c *nf.Ctx) error {
	type Req struct {
		State    string `query:"state"`
		Code     string `query:"code"`
		Scope    string `query:"scope"`
		ClientId string `query:"client_id"`
	}

	var (
		err   error
		req   = new(Req)
		token *oauth2.Token
	)

	if err = c.QueryParser(req); err != nil {
		return resp.Resp400(c, err.Error())
	}

	if req.State != state {
		log.Error("[C] state mismatch, want = %s, got = %s", state, req.State)
		return c.Status(http.StatusBadRequest).SendString("Bad Request: state mismatch")
	}

	if token, err = config.Exchange(c.Context(), req.Code); err != nil {
		log.Error("[C] oauth config exchange err: %s", err.Error())
		return resp.Resp500(c, err.Error())
	}

	bs, _ := json.Marshal(token)
	log.Info("[C] oauth finally token =\n%s", string(bs))

	return resp.Resp200(c, token)
}