package controllers

import (
	"fmt"
	"net/http"

	beego "github.com/beego/beego/v2/server/web"

	oidc "github.com/coreos/go-oidc"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
)

// OidcController is the controller in oidc
type OidcController struct {
	beego.Controller
}

var oauth2Config oauth2.Config
var idTokenVerifier *oidc.IDTokenVerifier
var ctx context.Context

// Connect implements open id connection to openid provider
func (c *OidcController) Connect() {
	ctx = context.Background()

	// Initialize a provider by specifying dex's issuer URL.
	provider, err := oidc.NewProvider(ctx, "http://127.0.0.1:5556/dex")
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// Configure the OAuth2 config with the client values.
	oauth2Config = oauth2.Config{
		// client_id and client_secret of the client.
		ClientID:     "opencloud-search",
		ClientSecret: "ZXhhbXBsZS1hcHAtc2VjcmV0",

		// The redirectURL.
		RedirectURL: "http://127.0.0.1:8080/oidc-callback",

		// Discovery returns the OAuth2 endpoints.
		Endpoint: provider.Endpoint(),

		// "openid" is a required scope for OpenID Connect flows.
		//
		// Other scopes, such as "groups" can be requested.
		Scopes: []string{oidc.ScopeOpenID, "profile", "email", "groups"},
	}

	// Create an ID token parser.
	idTokenVerifier = provider.Verifier(&oidc.Config{ClientID: "opencloud-search"})

	//state := newState()
	c.Redirect(oauth2Config.AuthCodeURL("foobar"), http.StatusFound)

}

// Callback implements open id callback from openid provider
func (c *OidcController) Callback() {

	state := c.GetString("state")
	code := c.GetString("code")
	_ = state
	// Verify state.

	oauth2Token, err := oauth2Config.Exchange(ctx, code)
	if err != nil {
		fmt.Println(err.Error())
	}

	// Extract the ID Token from OAuth2 token.
	rawIDToken, ok := oauth2Token.Extra("id_token").(string)
	if !ok {
		// handle missing token
	}
	fmt.Println(rawIDToken)
	// Parse and verify ID Token payload.
	idToken, err := idTokenVerifier.Verify(ctx, rawIDToken)
	if err != nil {
		// handle error
	}

	// Extract custom claims.
	var claims struct {
		Email    string   `json:"email"`
		Verified bool     `json:"email_verified"`
		Groups   []string `json:"groups"`
	}
	if err := idToken.Claims(&claims); err != nil {
		// handle error
	}
	c.SetSession("login", claims.Email)
	c.Redirect("/user", http.StatusFound)
}
