package repository

import (
	"context"
	"time"

	"gateway/internal/model/notification"
	domentity "gateway/internal/model/notification/domain/entity"
	"gateway/internal/model/notification/domain/enum"
	domrepo "gateway/internal/model/notification/domain/repository"

	"go.mongodb.org/mongo-driver/v2/bson"
)

// MemoryNotificationRepository is an in-memory NotificationRepository for tests and local tooling.
type MemoryNotificationRepository struct {
	byID   map[string]*domentity.Notification
	byIdem map[string]*domentity.Notification
}

// NewMemoryNotificationRepository creates an empty in-memory store.
func NewMemoryNotificationRepository() *MemoryNotificationRepository {
	return &MemoryNotificationRepository{
		byID:   make(map[string]*domentity.Notification),
		byIdem: make(map[string]*domentity.Notification),
	}
}

func idemKey(tenantID string, kind enum.NotifyKind, key string) string {
	return tenantID + ":" + string(kind) + ":" + key
}

func (r *MemoryNotificationRepository) Insert(_ context.Context, data *domentity.Notification) error {
	if data.ID.IsZero() {
		data.ID = bson.NewObjectID()
	}
	now := time.Now().UTC().UnixNano()
	if data.CreateAt == nil {
		data.CreateAt = &now
	}
	if data.UpdateAt == nil {
		data.UpdateAt = &now
	}
	if data.OccurredAt == nil {
		data.OccurredAt = &now
	}
	k := idemKey(data.TenantID, data.Kind, data.IdempotencyKey)
	if _, exists := r.byIdem[k]; exists {
		return notification.ErrDuplicateIdempotency
	}
	r.byIdem[k] = data
	r.byID[data.ID.Hex()] = data
	return nil
}

func (r *MemoryNotificationRepository) FindByID(_ context.Context, tenantID, id string) (*domentity.Notification, error) {
	doc, ok := r.byID[id]
	if !ok || doc.TenantID != tenantID {
		return nil, notification.ErrNotFound
	}
	return doc, nil
}

func (r *MemoryNotificationRepository) FindByIdempotency(
	_ context.Context,
	tenantID string,
	kind enum.NotifyKind,
	idempotencyKey string,
) (*domentity.Notification, error) {
	doc, ok := r.byIdem[idemKey(tenantID, kind, idempotencyKey)]
	if !ok {
		return nil, notification.ErrNotFound
	}
	return doc, nil
}

func (r *MemoryNotificationRepository) UpdateDelivery(_ context.Context, tenantID, id string, update *domrepo.NotificationDeliveryUpdate) error {
	doc, ok := r.byID[id]
	if !ok || doc.TenantID != tenantID {
		return notification.ErrNotFound
	}
	doc.Status = update.Status
	doc.Attempts = update.Attempts
	doc.Provider = update.Provider
	doc.ProviderMessageID = update.ProviderMessageID
	doc.LastError = update.LastError
	doc.Body = update.Body
	doc.DeliveredAt = update.DeliveredAt
	return nil
}

func (r *MemoryNotificationRepository) Index20260520001UP(context.Context) error {
	return nil
}
