package sqlc

import (
	"context"

	"github.com/jackc/pgx/v5/pgxpool"

	"route256/loms/internal/domain/entity"
	"route256/loms/internal/domain/repository/outbox"
	"route256/loms/internal/infra/db/postgres"
)

type outboxRepo struct {
	db *pgxpool.Pool
}

func NewOutboxRepository(masterPool *pgxpool.Pool) *outboxRepo {
	return &outboxRepo{
		db: masterPool,
	}
}

func (r *outboxRepo) GetQuerier(ctx context.Context) *Queries {
	tx, ok := postgres.TxFromCtx(ctx)
	if ok {
		return New(tx)
	}

	return New(r.db)
}

func (r *outboxRepo) AddEvent(ctx context.Context, evt outbox.Event) error {
	querier := r.GetQuerier(ctx)

	return querier.OutboxInsert(ctx, &OutboxInsertParams{
		OrderID: int64(evt.OrderID),
		Topic:   evt.Topic,
		Key:     &evt.Key,
		Column4: evt.Payload,
	})
}

func (r *outboxRepo) WithNewEvents(ctx context.Context, limit int32, handler func(context.Context, outbox.Event) error) error {
	querier := r.GetQuerier(ctx)

	rows, err := querier.OutboxSelectForPublish(ctx, int32(limit))
	if err != nil {
		return err
	}
	if len(rows) == 0 {
		return nil
	}

	var sentIDs, errIDs []int64

	for _, row := range rows {
		ev := outbox.Event{
			ID:      row.ID,
			OrderID: entity.ID(row.OrderID),
			Topic:   row.Topic,
			Key:     *row.Key,
			Payload: row.Payload,
		}

		if err := handler(ctx, ev); err != nil {
			errIDs = append(errIDs, row.ID)
		} else {
			sentIDs = append(sentIDs, row.ID)
		}
	}

	if len(sentIDs) > 0 {
		if _, err := querier.OutboxMarkSent(ctx, sentIDs); err != nil {
			return err
		}
	}

	if len(errIDs) > 0 {
		if _, err := querier.OutboxMarkError(ctx, errIDs); err != nil {
			return err
		}
	}

	return nil
}
