package port

import (
	"gitea.dwysokinski.me/twhelp/corev3/internal/app"
	"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
	"gitea.dwysokinski.me/twhelp/corev3/internal/watermill/watermillmsg"
	"github.com/ThreeDotsLabs/watermill"
	"github.com/ThreeDotsLabs/watermill/message"
)

type PlayerWatermillConsumer struct {
	svc                     *app.PlayerService
	snapshotSvc             *app.PlayerSnapshotService
	subscriber              message.Subscriber
	logger                  watermill.LoggerAdapter
	marshaler               watermillmsg.Marshaler
	eventServerSyncedTopic  string
	cmdCreateSnapshotsTopic string
	cmdCleanUpTopic         string
}

func NewPlayerWatermillConsumer(
	svc *app.PlayerService,
	snapshotSvc *app.PlayerSnapshotService,
	subscriber message.Subscriber,
	logger watermill.LoggerAdapter,
	marshaler watermillmsg.Marshaler,
	eventServerSyncedTopic string,
	cmdCreateSnapshotsTopic string,
	cmdCleanUpTopic string,
) *PlayerWatermillConsumer {
	return &PlayerWatermillConsumer{
		svc:                     svc,
		snapshotSvc:             snapshotSvc,
		subscriber:              subscriber,
		logger:                  logger,
		marshaler:               marshaler,
		eventServerSyncedTopic:  eventServerSyncedTopic,
		cmdCreateSnapshotsTopic: cmdCreateSnapshotsTopic,
		cmdCleanUpTopic:         cmdCleanUpTopic,
	}
}

func (c *PlayerWatermillConsumer) Register(router *message.Router) {
	router.AddNoPublisherHandler(
		"PlayerConsumer.sync",
		c.eventServerSyncedTopic,
		c.subscriber,
		c.sync,
	)
	router.AddNoPublisherHandler(
		"PlayerConsumer.createSnapshots",
		c.cmdCreateSnapshotsTopic,
		c.subscriber,
		c.createSnapshots,
	)
	router.AddNoPublisherHandler(
		"PlayerConsumer.cleanUp",
		c.cmdCleanUpTopic,
		c.subscriber,
		c.cleanUp,
	)
}

func (c *PlayerWatermillConsumer) sync(msg *message.Message) error {
	var rawPayload watermillmsg.ServerSyncedEventPayload

	if err := c.marshaler.Unmarshal(msg, &rawPayload); err != nil {
		c.logger.Error("couldn't unmarshal payload", err, watermill.LogFields{
			"handler": message.HandlerNameFromCtx(msg.Context()),
		})
		return nil
	}

	payload, err := domain.NewServerSyncedEventPayload(rawPayload.Key, rawPayload.URL, rawPayload.VersionCode)
	if err != nil {
		c.logger.Error("couldn't construct domain.ServerSyncedEventPayload", err, watermill.LogFields{
			"handler": message.HandlerNameFromCtx(msg.Context()),
		})
		return nil
	}

	return c.svc.Sync(msg.Context(), payload)
}

func (c *PlayerWatermillConsumer) createSnapshots(msg *message.Message) error {
	var rawPayload watermillmsg.CreateSnapshotsCmdPayload

	if err := c.marshaler.Unmarshal(msg, &rawPayload); err != nil {
		c.logger.Error("couldn't unmarshal payload", err, watermill.LogFields{
			"handler": message.HandlerNameFromCtx(msg.Context()),
		})
		return nil
	}

	payload, err := domain.NewCreateSnapshotsCmdPayload(
		rawPayload.ServerKey,
		rawPayload.VersionCode,
		rawPayload.VersionTimezone,
		rawPayload.Date,
	)
	if err != nil {
		c.logger.Error("couldn't construct domain.CreateSnapshotsCmdPayload", err, watermill.LogFields{
			"handler": message.HandlerNameFromCtx(msg.Context()),
		})
		return nil
	}

	return c.snapshotSvc.Create(msg.Context(), payload)
}

func (c *PlayerWatermillConsumer) cleanUp(msg *message.Message) error {
	var rawPayload watermillmsg.CleanUpDataCmdPayload

	if err := c.marshaler.Unmarshal(msg, &rawPayload); err != nil {
		c.logger.Error("couldn't unmarshal payload", err, watermill.LogFields{
			"handler": message.HandlerNameFromCtx(msg.Context()),
		})
		return nil
	}

	payloadServer, err := domain.NewCleanUpDataCmdPayloadServer(
		rawPayload.Server.Key,
		rawPayload.Server.VersionCode,
		rawPayload.Server.Open,
		rawPayload.Server.Special,
		rawPayload.Server.PlayerDataSyncedAt,
		rawPayload.Server.PlayerSnapshotsCreatedAt,
		rawPayload.Server.TribeDataSyncedAt,
		rawPayload.Server.TribeSnapshotsCreatedAt,
		rawPayload.Server.VillageDataSyncedAt,
		rawPayload.Server.EnnoblementDataSyncedAt,
	)
	if err != nil {
		c.logger.Error("couldn't construct domain.CleanUpDataCmdPayloadServer", err, watermill.LogFields{
			"handler": message.HandlerNameFromCtx(msg.Context()),
		})
		return nil
	}

	payload, err := domain.NewCleanUpDataCmdPayload(payloadServer)
	if err != nil {
		c.logger.Error("couldn't construct domain.CleanUpDataCmdPayload", err, watermill.LogFields{
			"handler": message.HandlerNameFromCtx(msg.Context()),
		})
		return nil
	}

	return c.snapshotSvc.CleanUp(msg.Context(), payload)
}
