package app

import (
	"context"
	"fmt"

	"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
)

type DataSyncService struct {
	versionSvc     *VersionService
	serverSvc      *ServerService
	serverPub      ServerPublisher
	ennoblementPub EnnoblementPublisher
}

func NewDataSyncService(
	versionSvc *VersionService,
	serverSvc *ServerService,
	serverPub ServerPublisher,
	ennoblementPub EnnoblementPublisher,
) *DataSyncService {
	return &DataSyncService{
		versionSvc:     versionSvc,
		serverSvc:      serverSvc,
		serverPub:      serverPub,
		ennoblementPub: ennoblementPub,
	}
}

func (svc *DataSyncService) TriggerDataSync(ctx context.Context) error {
	versions, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
	if err != nil {
		return err
	}

	payloads := make([]domain.SyncServersCmdPayload, 0, len(versions))

	for _, v := range versions {
		p, payloadErr := domain.NewSyncServersCmdPayload(v.Code(), v.URL())
		if payloadErr != nil {
			return fmt.Errorf("%s: couldn't construct domain.SyncServersCmdPayload: %w", v.Code(), payloadErr)
		}

		payloads = append(payloads, p)
	}

	return svc.serverPub.CmdSync(ctx, payloads...)
}

func (svc *DataSyncService) TriggerEnnoblementSync(ctx context.Context) error {
	versions, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
	if err != nil {
		return err
	}

	for _, v := range versions {
		if err = svc.triggerEnnoblementSyncForVersion(ctx, v); err != nil {
			return fmt.Errorf("%s: %w", v.Code(), err)
		}
	}

	return nil
}

func (svc *DataSyncService) triggerEnnoblementSyncForVersion(ctx context.Context, v domain.Version) error {
	servers, err := svc.serverSvc.ListAllOpen(ctx, v.Code())
	if err != nil {
		return err
	}

	payloads := make([]domain.SyncEnnoblementsCmdPayload, 0, len(servers))

	for _, s := range servers {
		p, payloadErr := domain.NewSyncEnnoblementsCmdPayload(s.Key(), s.URL(), s.VersionCode())
		if payloadErr != nil {
			return fmt.Errorf("%s: couldn't construct domain.SyncEnnoblementsCmdPayload: %w", s.Key(), payloadErr)
		}

		payloads = append(payloads, p)
	}

	return svc.ennoblementPub.CmdSync(ctx, payloads...)
}
