package auth

import (
	"context"

	"code.justin.tv/live/autohost/internal/hosting/clients/hallpass"
	"code.justin.tv/live/autohost/internal/hosting/clients/users"
)

type Auth interface {
	CanUseHosting(ctx context.Context, callerID string, channelID string) (bool, error)
	CanEditChannelSettings(ctx context.Context, callerID string, channelID string) (bool, error)
}

func NewAuth(hallpassClient hallpass.Client, usersClient users.Client) Auth {
	return &authImpl{
		HallpassClient: hallpassClient,
		UsersClient:    usersClient,
	}
}

type authImpl struct {
	HallpassClient hallpass.Client
	UsersClient    users.Client
}

var _ Auth = &authImpl{}

func (s *authImpl) CanUseHosting(ctx context.Context, callerID string, channelID string) (bool, error) {
	if callerID == channelID {
		return true, nil
	}

	isEditor, err := s.isEditor(ctx, callerID, channelID)
	if err != nil {
		return false, err
	}
	if isEditor {
		return true, nil
	}

	return s.isStaff(ctx, callerID)
}

// CanEditChannel authorizes a user to edit a given channel.
func (s *authImpl) CanEditChannelSettings(ctx context.Context, callerID string, channelID string) (bool, error) {
	if callerID == channelID {
		return true, nil
	}

	return s.isEditor(ctx, callerID, channelID)
}

func (s *authImpl) isEditor(ctx context.Context, userID string, channelID string) (bool, error) {
	resp, err := s.HallpassClient.GetV1IsEditor(ctx, channelID, userID, nil)
	if err != nil {
		return false, err
	}
	if resp == nil {
		return false, nil
	}

	return resp.IsEditor, nil
}

func (s *authImpl) isStaff(ctx context.Context, userID string) (bool, error) {
	user, err := s.UsersClient.GetUserByID(ctx, userID, nil)
	if err != nil {
		return false, err
	}
	if user == nil || user.Admin == nil {
		return false, nil
	}

	return *user.Admin, nil
}

// isAdmin checks whether a user is a Twitch admin or staff.
func (s *authImpl) isAdminOrStaff(ctx context.Context, userID string) (bool, error) {
	if userID == "" {
		return false, nil
	}

	user, err := s.UsersClient.GetUserByID(ctx, userID, nil)
	if err != nil {
		return false, err
	}

	if user == nil || user.Subadmin == nil || user.Admin == nil {
		return false, nil
	}

	return *user.Subadmin || *user.Admin, nil
}
