package main

import (
	"errors"
	"oc-auth/conf"
	"oc-auth/infrastructure"
	_ "oc-auth/routers"
	"os"
	"strconv"
	"strings"

	oclib "cloud.o-forge.io/core/oc-lib"
	peer "cloud.o-forge.io/core/oc-lib/models/peer"
	"cloud.o-forge.io/core/oc-lib/models/utils"
	"cloud.o-forge.io/core/oc-lib/tools"
	beego "github.com/beego/beego/v2/server/web"
)

const test_name = "test-pierre"
const appname = "oc-auth"

// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.
func main() {
	// Init the oc-lib
	oclib.Init(appname)
	// Load the right config file
	o := oclib.GetConfLoader()

	conf.GetConfig().AdminRole = o.GetStringDefault("ADMIN_ROLE", "admin")
	conf.GetConfig().PublicKeyPath = o.GetStringDefault("PUBLIC_KEY_PATH", "./pem/public.pem")
	conf.GetConfig().PrivateKeyPath = o.GetStringDefault("PRIVATE_KEY_PATH", "./pem/private.pem")
	conf.GetConfig().ClientSecret = o.GetStringDefault("CLIENT_SECRET", "oc-auth-got-secret")

	conf.GetConfig().Auth = o.GetStringDefault("AUTH", "hydra")
	conf.GetConfig().AuthConnectorHost = o.GetStringDefault("AUTH_CONNECTOR_HOST", "localhost")
	conf.GetConfig().AuthConnectorPort = o.GetIntDefault("AUTH_CONNECTOR_PORT", 4444)
	conf.GetConfig().AuthConnectorAdminPort = o.GetIntDefault("AUTH_CONNECTOR_ADMIN_PORT", 4445)
	conf.GetConfig().PermissionConnectorHost = o.GetStringDefault("PERMISSION_CONNECTOR_HOST", "keto")
	conf.GetConfig().PermissionConnectorPort = o.GetIntDefault("PERMISSION_CONNECTOR_PORT", 4466)
	conf.GetConfig().PermissionConnectorAdminPort = o.GetIntDefault("PERMISSION_CONNECTOR_ADMIN_PORT", 4467)

	// config LDAP
	conf.GetConfig().LDAPEndpoints = o.GetStringDefault("LDAP_ENDPOINTS", "ldap:389")
	conf.GetConfig().LDAPBindDN = o.GetStringDefault("LDAP_BINDDN", "cn=admin,dc=example,dc=com")
	conf.GetConfig().LDAPBindPW = o.GetStringDefault("LDAP_BINDPW", "password")
	conf.GetConfig().LDAPBaseDN = o.GetStringDefault("LDAP_BASEDN", "dc=example,dc=com")
	conf.GetConfig().LDAPRoleBaseDN = o.GetStringDefault("LDAP_ROLE_BASEDN", "ou=AppRoles,dc=example,dc=com")
	err := generateSelfPeer()
	if err != nil {
		panic(err)
	}
	discovery()
	beego.Run()
}

func generateSelfPeer() error {
	requester := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), test_name, "1234", nil, nil)

	// TODO check if files at private & public path are set
	// check if files at private & public path are set
	if _, err := os.Stat(conf.GetConfig().PrivateKeyPath); errors.Is(err, os.ErrNotExist) {
		return errors.New("private key path does not exist")
	}
	if _, err := os.Stat(conf.GetConfig().PublicKeyPath); errors.Is(err, os.ErrNotExist) {
		return errors.New("public key path does not exist")
	}
	// check if peer already exists
	p := requester.Search(nil,strconv.Itoa(peer.SELF.EnumIndex()))
	// p := oclib.Search(nil, strconv.Itoa(peer.SELF.EnumIndex()), oclib.L	ibDataEnum(oclib.PEER))
	file := ""
	f, err := os.ReadFile(conf.GetConfig().PublicKeyPath)
	if err != nil {
		return err
	}
	file = string(f)
	if len(p.Data) > 0 {
		// check public key with the one in the database
		// compare the public key from file with the one in the database
		if !strings.Contains(file, p.Data[0].(*peer.Peer).PublicKey) {
			return errors.New("public key is different from the one in the database")
		}
		return nil
	}
	// create a new peer
	o := oclib.GetConfLoader()
	peer := &peer.Peer{
		Url: o.GetStringDefault("HOSTNAME", "http://localhost"),
		AbstractObject: utils.AbstractObject{
			Name: o.GetStringDefault("NAME", "local"),
		},
		PublicKey: file,
		State:     peer.SELF,
	}
	data := requester.StoreOne(peer.Serialize(peer))
	if data.Err != "" {
		return errors.New(data.Err)
	}
	return nil
}

func discovery() {
	api := tools.API{}
	conn := infrastructure.GetPermissionConnector()

	conn.CreateRole(conf.GetConfig().AdminRole)
	conn.BindRole(conf.GetConfig().AdminRole, "admin")
	addPermissions := func(m map[string]interface{}) {
		for k, v := range m {
			for _, p := range v.([]interface{}) {
				conn.CreatePermission(k, p.(string), true)
			}
		}
	}
	api.ListenRouter(addPermissions)
	tools.NewNATSCaller().SetNATSPub("api", tools.DISCOVERY, map[string]interface{}{})
}
