package auditlog

import (
	"context"
	"strconv"

	"code.justin.tv/eventbus/controlplane/internal/db"
	"code.justin.tv/eventbus/controlplane/internal/ldap"
	"code.justin.tv/eventbus/controlplane/internal/logger"
	"code.justin.tv/eventbus/controlplane/rpc"

	"github.com/golang/protobuf/ptypes"
	"github.com/pkg/errors"
	"github.com/twitchtv/twirp"
	"go.uber.org/zap"
)

type AuditLogService struct {
	DB db.DB
}

func (s *AuditLogService) GetAuditLogsForService(ctx context.Context, req *rpc.GetAuditLogsForServiceReq) (*rpc.GetAuditLogsForServiceResp, error) {
	log := logger.FromContext(ctx)
	if req.ServiceId == "" {
		return nil, twirp.NewError(twirp.InvalidArgument, "must provide id of service to get audit logs for")
	}

	serviceID, err := strconv.Atoi(req.ServiceId)
	if err != nil {
		return nil, twirp.NewError(twirp.InvalidArgument, "could not convert service id to int "+req.ServiceId)
	}

	service, err := s.DB.ServiceByID(ctx, serviceID)
	if err == db.ErrServiceNotFound {
		return nil, twirp.NewError(twirp.InvalidArgument, "service "+req.ServiceId+" does not exist")
	} else if err != nil {
		return nil, twirp.NewError(twirp.Internal, "unable to fetch service for update")
	}

	if !ldap.BelongsToGroup(ctx, service.LDAPGroup) {
		return nil, twirp.NewError(twirp.PermissionDenied, "user must belong to ldap group of created service")
	}

	als, err := s.DB.AuditLogsByServiceID(ctx, serviceID)
	if err != nil {
		return nil, errors.Wrapf(err, "could not get audit logs for provided service %q", serviceID)
	}

	var alProtos []*rpc.AuditLog
	for _, al := range als {
		ts, err := ptypes.TimestampProto(al.Timestamp)
		if err != nil {
			log.Error("could not parse timestamp in audit log", zap.Object("auditLog", al), zap.Error(err))
		}

		alProtos = append(alProtos, &rpc.AuditLog{
			ServiceId:    strconv.Itoa(al.ServiceID),
			UserName:     al.UserName,
			ResourceType: al.ResourceType,
			ResourceName: al.ResourceName,
			Result:       al.Result,
			Action:       al.Action,
			Timestamp:    ts,
			Before:       al.Before.String(),
			After:        al.After.String(),
		})
	}
	return &rpc.GetAuditLogsForServiceResp{
		AuditLogs: alProtos,
	}, nil
}
