package auth

import (
	"crypto/rsa"
	"net/http"
	"net/http/httputil"
	"slices"

	"github.com/gookit/goutil/dump"
	"github.com/zeevdiukman/zprox/internal/config"
	"github.com/zeevdiukman/zprox/internal/session"
	"golang.org/x/oauth2"
)

func Middleware(routerData *config.Router, routeID string, w http.ResponseWriter, r *http.Request, rp *httputil.ReverseProxy) {
	authConfig := config.Data.AuthMap[routerData.Auth.Provider]

	// dump.P("routerData.Auth.Provider", routerData.Auth.Provider)
	// dump.P("authConfig.OpenID.EndPoints.RedirectURI", authConfig.OpenID.EndPoints.RedirectURI)
	// dump.P("config.Data.AuthMap[routerData.Auth.Provider]", config.Data.AuthMap[routerData.Auth.Provider].OpenID.EndPoints.RedirectURI)
	if !routerData.IsAuthRouter && !IsLoggedIn(r, authConfig, routerData, routeID) {
		RedirectToLogin(authConfig, w, r)

		return
	}
	rp.ServeHTTP(w, r)

}

// func IsLoggedIn(r *http.Request, routerData *config.Router, routeID string) bool {
// 	if oauth2Token, ok := session.Manager.Get(r.Context(), "oauth2_token").(*oauth2.Token); ok {
// 		if publicKey, ok := session.Manager.Get(r.Context(), "jwks_public_key").(*rsa.PublicKey); ok {
// 			if claims, isValid := GetJwtClaims(r, publicKey, oauth2Token); isValid {
// 				allowLists := routerData.Auth.JWT.AllowLists
// 				for listName, list := range allowLists {
// 					if len(list) > 0 {
// 						if claim, ok := claims[listName]; ok {
// 							if !slices.Contains(list, claim.(string)) {
// 								return false
// 							} else {
// 								dump.P("Hello " + claims["name"].(string))
// 							}

// 						}
// 					}
// 				}
// 			}
// 			if !oauth2Token.Valid() {
// 				return false
// 			}
// 		}
// 		dump.P("IsLoggedIn: token is not valid")
// 		return false

// 	}
// 	dump.P("IsLoggedIn: no token")

//		return false
//	}
func IsLoggedIn(r *http.Request, authConfig *config.Auth, routerData *config.Router, routeID string) bool {
	var oauth2Token *oauth2.Token
	var publicKey *rsa.PublicKey
	var oauth2TokenOK bool
	var publicKeyOK bool
	if oauth2Token, oauth2TokenOK = session.Manager.Get(r.Context(), "oauth2_token").(*oauth2.Token); !oauth2TokenOK {
		// dump.P("no oauth2Token")

		return false
	}
	if publicKey, publicKeyOK = session.Manager.Get(r.Context(), "jwks_public_key").(*rsa.PublicKey); !publicKeyOK {
		dump.P("publicKey not valid")

		return false
	}
	if !oauth2Token.Valid() {
		dump.P("oauth2Token not valid")
		return false
	}

	claims, err := GetJwtClaims(r, publicKey, oauth2Token)
	if err != nil {
		dump.P(err.Error())
		return false
	}
	if err := claims.Valid(); err != nil {
		dump.P(err.Error())

		return false
	}

	// dump.P(claims)
	// conf := &oauth2.Config{
	// 	ClientID:     authConfig.OpenID.ClientID,
	// 	ClientSecret: authConfig.OpenID.ClientSecret,
	// 	RedirectURL:  authConfig.OpenID.RedirectURI,
	// 	Scopes:       []string{"openid", "email", "profile"},
	// 	Endpoint: oauth2.Endpoint{
	// 		AuthURL:  authConfig.OpenID.AuthURL,
	// 		TokenURL: authConfig.OpenID.TokenURL,
	// 	},
	// }
	// u,_ := url.Parse(authConfig.OpenID.UserURL)
	// u.
	// client := conf.Client(r.Context(),oauth2Token)
	// client.PostForm(authConfig.OpenID.UserURL,url.Values{})
	// tokenSource := conf.TokenSource(r.Context(), oauth2Token)
	// tokenSource.Token()
	// if !oauth2Token.Valid() {

	// timeNow := time.Now()
	// if !oauth2Token.Expiry.Before(timeNow) {
	// 	return false
	// }
	// openID := config.Data.AuthMap[routerData.Auth.Provider].OpenID
	// conf := &oauth2.Config{
	// 	ClientID:     openID.ClientID,
	// 	ClientSecret: openID.ClientSecret,
	// 	RedirectURL:  openID.RedirectURI,
	// 	Scopes:       []string{"openid", "email", "profile"},
	// 	Endpoint:     endPoint,
	// }

	// oauth2Token, err := conf.Exchange(r.Context(), code)
	// if err != nil {
	// 	return false
	// 	log.Println(err.Error())
	// }
	// 	return false
	// }

	for listName, list := range routerData.Auth.JWT.AllowLists {
		if len(list) > 0 {
			if claim, ok := claims[listName]; ok {
				if !slices.Contains(list, claim.(string)) {
					return false
				} else {
					dump.P("Hello " + claims["name"].(string))
				}
			}
		}
	}

	return true
}

// func getAccessToken(refreshToken string) (TokenResponse, error) {
// 	keycloakURL := os.Getenv("KEYCLOAK_URL")
// 	realm := os.Getenv("KEYCLOAK_REALM")
// 	clientID := os.Getenv("KEYCLOAK_CLIENT_ID")
// 	clientSecret := os.Getenv("KEYCLOAK_CLIENT_SECRET")

// 	tokenURL := fmt.Sprintf("%s/auth/realms/%s/protocol/openid-connect/token", keycloakURL, realm)

// 	data := url.Values{}
// 	data.Set("grant_type", "refresh_token")
// 	data.Set("client_id", clientID)
// 	data.Set("client_secret", clientSecret)
// 	data.Set("refresh_token", refreshToken)

// 	req, err := http.NewRequest("POST", tokenURL, bytes.NewBufferString(data.Encode()))
// 	if err != nil {
// 		return TokenResponse{}, err
// 	}

// 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

// 	client := &http.Client{}
// 	resp, err := client.Do(req)
// 	if err != nil {
// 		return TokenResponse{}, err
// 	}
// 	defer resp.Body.Close()

// 	body, err := io.ReadAll(resp.Body)
// 	if err != nil {
// 		return TokenResponse{}, err
// 	}

// 	if resp.StatusCode != http.StatusOK {
// 		return TokenResponse{}, fmt.Errorf("Keycloak returned status: %d, body: %s", resp.StatusCode, string(body))
// 	}

// 	var tokenResponse TokenResponse
// 	err = json.Unmarshal(body, &tokenResponse)
// 	if err != nil {
// 		return TokenResponse{}, err
// 	}

// 	return tokenResponse, nil
// }
