package config

import (
	"context"
	"errors"

	"github.com/Nerzal/gocloak/v13"
)

// MinioSetup struct
type KeycloakConfig struct {
	Cfg *Config
}

func NewKeycloakConfig(cfg *Config) *KeycloakConfig {
	keycloakSetup := &KeycloakConfig{
		Cfg: cfg,
	}

	return keycloakSetup
}

func (_keycloak *KeycloakConfig) Login(username string, password string) (*gocloak.JWT, error) {
	ctx := context.Background()
	client := gocloak.NewClient(_keycloak.Cfg.Keycloak.Endpoint)
	loginResponse, err := client.Login(
		ctx,
		_keycloak.Cfg.Keycloak.ClientId,
		_keycloak.Cfg.Keycloak.ClientSecret,
		_keycloak.Cfg.Keycloak.Realm,
		username,
		password,
	)
	if err != nil {
		return nil, errors.New("Invalid User Credentials")
	}

	return loginResponse, nil
}

func (_keycloak *KeycloakConfig) RefreshToken(refreshToken string) (*gocloak.JWT, error) {
	ctx := context.Background()
	client := gocloak.NewClient(_keycloak.Cfg.Keycloak.Endpoint)
	loginResponse, err := client.RefreshToken(
		ctx,
		refreshToken,
		_keycloak.Cfg.Keycloak.ClientId,
		_keycloak.Cfg.Keycloak.ClientSecret,
		_keycloak.Cfg.Keycloak.Realm,
	)
	if err != nil {
		return nil, errors.New("Invalid User Credentials")
	}

	return loginResponse, nil
}

func (_keycloak *KeycloakConfig) CreateUser(fullname string, email string, username string, password string) (string, error) {
	ctx := context.Background()
	client := gocloak.NewClient(_keycloak.Cfg.Keycloak.Endpoint)
	token, err := client.Login(
		ctx,
		_keycloak.Cfg.Keycloak.ClientId,
		_keycloak.Cfg.Keycloak.ClientSecret,
		_keycloak.Cfg.Keycloak.Realm,
		_keycloak.Cfg.Keycloak.AdminUsername,
		_keycloak.Cfg.Keycloak.AdminPassword,
	)
	if err != nil {
		panic("Something wrong with the credentials or url")
	}

	var group []string
	group = append(group, "narasi-ahli")
	user := gocloak.User{
		FirstName: gocloak.StringP(fullname),
		LastName:  gocloak.StringP(fullname),
		Email:     gocloak.StringP(email),
		Enabled:   gocloak.BoolP(true),
		Username:  gocloak.StringP(username),
		Groups:    &group,
	}

	keycloakId, err := client.CreateUser(ctx, token.AccessToken, _keycloak.Cfg.Keycloak.Realm, user)
	if err != nil {
		panic("Oh no!, failed to create user :(..")
	}

	err = _keycloak.SetPassword(token.AccessToken, keycloakId, password)
	if err != nil {
		return "", err
	}

	return keycloakId, nil
}

func (_keycloak *KeycloakConfig) UpdateUser(keycloakId *string, fullname string, email string) error {
	ctx := context.Background()
	client := gocloak.NewClient(_keycloak.Cfg.Keycloak.Endpoint)
	token, err := client.Login(
		ctx,
		_keycloak.Cfg.Keycloak.ClientId,
		_keycloak.Cfg.Keycloak.ClientSecret,
		_keycloak.Cfg.Keycloak.Realm,
		_keycloak.Cfg.Keycloak.AdminUsername,
		_keycloak.Cfg.Keycloak.AdminPassword,
	)
	if err != nil {
		panic("Something wrong with the credentials or url")
	}

	var group []string
	group = append(group, "narasi-ahli")
	user := gocloak.User{
		ID:        keycloakId,
		FirstName: gocloak.StringP(fullname),
		LastName:  gocloak.StringP(fullname),
		Email:     gocloak.StringP(email),
		Groups:    &group,
	}

	err = client.UpdateUser(ctx, token.AccessToken, _keycloak.Cfg.Keycloak.Realm, user)
	if err != nil {
		panic(err)
	}

	return err
}

func (_keycloak *KeycloakConfig) SetPassword(token string, keycloakId string, password string) error {
	ctx := context.Background()
	client := gocloak.NewClient(_keycloak.Cfg.Keycloak.Endpoint)

	err := client.SetPassword(ctx, token, keycloakId, _keycloak.Cfg.Keycloak.Realm, password, false)
	if err != nil {
		panic("Oh no!, failed to set password :(")
	}

	return nil
}

func (_keycloak *KeycloakConfig) SetPasswordWithoutToken(keycloakId string, password string) error {
	ctx := context.Background()
	client := gocloak.NewClient(_keycloak.Cfg.Keycloak.Endpoint)

	token, err := client.Login(
		ctx,
		_keycloak.Cfg.Keycloak.ClientId,
		_keycloak.Cfg.Keycloak.ClientSecret,
		_keycloak.Cfg.Keycloak.Realm,
		_keycloak.Cfg.Keycloak.AdminUsername,
		_keycloak.Cfg.Keycloak.AdminPassword,
	)
	if err != nil {
		panic("Something wrong with the credentials or url")
	}

	err = client.SetPassword(ctx, token.AccessToken, keycloakId, _keycloak.Cfg.Keycloak.Realm, password, false)
	if err != nil {
		panic("Oh no!, failed to set password :(")
	}

	return nil
}

func (_keycloak *KeycloakConfig) GetUserSessions() ([]*gocloak.UserSessionRepresentation, error) {
	ctx := context.Background()
	client := gocloak.NewClient(_keycloak.Cfg.Keycloak.Endpoint)

	token, err := client.Login(
		ctx,
		_keycloak.Cfg.Keycloak.ClientId,
		_keycloak.Cfg.Keycloak.ClientSecret,
		_keycloak.Cfg.Keycloak.Realm,
		_keycloak.Cfg.Keycloak.AdminUsername,
		_keycloak.Cfg.Keycloak.AdminPassword,
	)
	if err != nil {
		panic("Something wrong with the credentials or url")
	}

	sessionData, err := client.GetClientUserSessions(ctx, token.AccessToken, _keycloak.Cfg.Keycloak.Realm, _keycloak.Cfg.Keycloak.ClientId)
	if err != nil {
		panic("Oh no!, failed to set password :(")
	}

	return sessionData, nil
}
