package service

import (
	"context"
	"errors"
	"git.itzana.me/strafesnet/go-grpc/auth"
	"git.itzana.me/strafesnet/maps-service/pkg/api"
)

var (
	// ErrMissingSessionID there is no session id
	ErrMissingSessionID = errors.New("SessionID missing")
	// ErrInvalidSession caller does not have a valid session
	ErrInvalidSession = errors.New("Session invalid")
)

type Role int32
var (
	// has ScriptWrite
	RoleQuat Role = 240
	// has SubmissionPublish
	RoleMapAdmin Role = 128
	// has SubmissionReview
	RoleMapCouncil Role = 64
)

type UserInfo struct {
	// Would love to know a better way to do this
	svc       *SecurityHandler
	ctx       *context.Context
	sessionId string
}

func (usr UserInfo) GetUserID() (uint64, error) {
	session, err := usr.svc.Client.GetSessionUser(*usr.ctx, &auth.IdMessage{
		SessionID: usr.sessionId,
	})
	if err != nil {
		return 0, err
	}
	return session.UserID, nil
}
func (usr UserInfo) IsSubmitter(submitter uint64) (bool, error) {
	userId, err := usr.GetUserID()
	if err != nil {
		return false, err
	}
	return userId == submitter, nil
}
func (usr UserInfo) hasRole(role Role) (bool, error) {
	roles, err := usr.svc.Client.GetGroupRole(*usr.ctx, &auth.IdMessage{
		SessionID: usr.sessionId,
	})
	if err != nil {
		return false, err
	}

	for _, r := range roles.Roles {
		if int32(role) <= r.Rank {
			return true, nil
		}
	}
	return false, nil
}


// RoleThumbnail
// RoleMapDownload
func (usr UserInfo) HasRoleSubmissionRelease() (bool, error) {
	return usr.hasRole(RoleMapAdmin)
}
func (usr UserInfo) HasRoleSubmissionReview() (bool, error) {
	return usr.hasRole(RoleMapCouncil)
}
func (usr UserInfo) HasRoleScriptWrite() (bool, error) {
	return usr.hasRole(RoleQuat)
}
/// Not implemented
func (usr UserInfo) HasRoleMaptest() (bool, error) {
	println("HasRoleMaptest is not implemented!")
	return false, nil
}

type SecurityHandler struct {
	Client auth.AuthServiceClient
}

func (svc SecurityHandler) HandleCookieAuth(ctx context.Context, operationName api.OperationName, t api.CookieAuth) (context.Context, error) {
	sessionId := t.GetAPIKey()
	if sessionId == "" {
		return nil, ErrMissingSessionID
	}

	validate, err := svc.Client.ValidateSession(ctx, &auth.IdMessage{
		SessionID: sessionId,
	})
	if err != nil {
		return nil, err
	}
	if !validate.Valid {
		return nil, ErrInvalidSession
	}

	newCtx := context.WithValue(ctx, "UserInfo", UserInfo{
		svc:       &svc,
		ctx:       &ctx,
		sessionId: sessionId,
	})

	return newCtx, nil
}