package service

import (
	"context"
	"encoding/json"

	"git.itzana.me/strafesnet/maps-service/pkg/api"
	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
	"git.itzana.me/strafesnet/maps-service/pkg/model"
)

// CreateMapfixAuditComment implements createMapfixAuditComment operation.
//
// Post a comment to the audit log
//
// POST /mapfixes/{MapfixID}/comment
func (svc *Service) CreateMapfixAuditComment(ctx context.Context, req api.CreateMapfixAuditCommentReq, params api.CreateMapfixAuditCommentParams) (error) {
	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
	if !ok {
		return ErrUserInfo
	}

	has_role, err := userInfo.HasRoleMapfixReview()
	if err != nil {
		return err
	}
	if !has_role {
		return ErrPermissionDeniedNeedRoleMapfixReview
	}

	userId, err := userInfo.GetUserID()
	if err != nil {
		return err
	}

	data := []byte{}
	_, err = req.Read(data)
	if err != nil {
		return err
	}
	Comment := string(data)

	event_data := model.AuditEventDataComment{
		Comment: Comment,
	}

	EventData, err := json.Marshal(event_data)
	if err != nil {
		return err
	}

	_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
		ID:           0,
		User:         userId,
		ResourceType: model.ResourceMapfix,
		ResourceID:   params.MapfixID,
		EventType:    model.AuditEventTypeComment,
		EventData:    EventData,
	})
	if err != nil {
		return err
	}

	return nil
}

// ListMapfixAuditEvents invokes listMapfixAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /mapfixes/{MapfixID}/audit-events
func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMapfixAuditEventsParams) ([]api.AuditEvent, error) {
	filter := datastore.Optional()

	filter.Add("resource_type", model.ResourceMapfix)
	filter.Add("resource_id", params.MapfixID)

	items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
		Number: params.Page,
		Size:   params.Limit,
	})
	if err != nil {
		return nil, err
	}

	var resp []api.AuditEvent
	for _, item := range items {
		EventData := api.AuditEventEventData{}
		err = EventData.UnmarshalJSON(item.EventData)
		if err != nil {
			return nil, err
		}
		resp = append(resp, api.AuditEvent{
			ID:           item.ID,
			Date:         item.CreatedAt.Unix(),
			User:         int64(item.User),
			ResourceType: int32(item.ResourceType),
			ResourceID:   item.ResourceID,
			EventType:    int32(item.EventType),
			EventData:    EventData,
		})
	}

	return resp, nil
}

// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
//
// Post a comment to the audit log
//
// POST /submissions/{SubmissionID}/comment
func (svc *Service) CreateSubmissionAuditComment(ctx context.Context, req api.CreateSubmissionAuditCommentReq, params api.CreateSubmissionAuditCommentParams) (error) {
	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
	if !ok {
		return ErrUserInfo
	}

	has_role, err := userInfo.HasRoleSubmissionReview()
	if err != nil {
		return err
	}
	if !has_role {
		return ErrPermissionDeniedNeedRoleSubmissionReview
	}

	userId, err := userInfo.GetUserID()
	if err != nil {
		return err
	}

	data := []byte{}
	_, err = req.Read(data)
	if err != nil {
		return err
	}
	Comment := string(data)

	event_data := model.AuditEventDataComment{
		Comment: Comment,
	}

	EventData, err := json.Marshal(event_data)
	if err != nil {
		return err
	}

	_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
		ID:           0,
		User:         userId,
		ResourceType: model.ResourceSubmission,
		ResourceID:   params.SubmissionID,
		EventType:    model.AuditEventTypeComment,
		EventData:    EventData,
	})
	if err != nil {
		return err
	}

	return nil
}

// ListSubmissionAuditEvents invokes listSubmissionAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /submissions/{SubmissionID}/audit-events
func (svc *Service) ListSubmissionAuditEvents(ctx context.Context, params api.ListSubmissionAuditEventsParams) ([]api.AuditEvent, error) {
	filter := datastore.Optional()

	filter.Add("resource_type", model.ResourceSubmission)
	filter.Add("resource_id", params.SubmissionID)

	items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
		Number: params.Page,
		Size:   params.Limit,
	})
	if err != nil {
		return nil, err
	}

	var resp []api.AuditEvent
	for _, item := range items {
		EventData := api.AuditEventEventData{}
		err = EventData.UnmarshalJSON(item.EventData)
		if err != nil {
			return nil, err
		}
		resp = append(resp, api.AuditEvent{
			ID:           item.ID,
			Date:         item.CreatedAt.Unix(),
			User:         int64(item.User),
			ResourceType: int32(item.ResourceType),
			ResourceID:   item.ResourceID,
			EventType:    int32(item.EventType),
			EventData:    EventData,
		})
	}

	return resp, nil
}