package notify

import (
	"context"
	"time"
)

// repository.go: kalıcılık sözleşmesi.
//
// Neden arayüz? Proje deseni (bkz. tool/contract.go, memory/repository.go):
// üretim Mongo, test bellek içi. RepositoryContract ÜRETİM KODUNDA olmalı —
// `_test.go` içinde olursa dış paketler erişemez.

// Kutu adları.
const (
	BoxInbox = "inbox" // bana gelenler
	BoxSent  = "sent"  // benim gönderdiklerim ve bana gelen yanıtlar
)

// Filter, bir gelen kutusu sorgusudur.
//
// KUTULAR NEDEN AYRI? Alıcının listesi (ToUserID = ben) ve soranın listesi
// (FromUserID = ben) farklı kayıtları gösterir: bana gönderilmiş sorular bir yerde,
// benim sorduğum soruların yanıtları diğerinde. Tek "inbox" sütunu ikisini
// birbirine karıştırırdı.
type Filter struct {
	Box         string
	Kind        Kind // boş = hepsi
	PendingOnly bool // yalnızca yanıt bekleyen sorular
	Limit       int  // 0 = sunucu varsayılanı
	Offset      int
}

// Repository, bildirimlerin kalıcı deposudur.
//
// TASARIM KURALI: FromName kayıt ANINDA çözülür ve saklanır. Sonradan kullanıcı adı
// değişse bile eski bildirim eski ismi gösterir (denetim izi doğru kalır). Bu
// yüzden depo, kullanıcı adını AYRICA sorgulamaz.
type Repository interface {
	// Create bildirimi ekler ve kaydedilmiş halini döndürür.
	Create(ctx context.Context, m Message) (Message, error)

	// Get tek bir bildirimi döndürür (ErrNotFound).
	Get(ctx context.Context, id string) (Message, error)

	// List kullanıcının kutusundaki bildirimleri yeniye önce sırayla döndürür;
	// ikinci değer toplam sayıdır (arayüz sayfalar).
	List(ctx context.Context, userID string, f Filter) ([]Message, int, error)

	// MarkRead alıcının bildirimi okundu işaretler. Yalnızca alıcı yapabilir
	// (aksi halde ErrForbidden).
	MarkRead(ctx context.Context, userID, id string, at time.Time) (Message, error)

	// Answer soruyu yanıtlar: soruyu "yanıtlandı" yapar ve yanıtı sorana AYRI bir
	// kayıt olarak yazar. userID sorunun ALICISI olmalıdır (aksi halde ErrForbidden).
	// Dönen ilk değer güncellenmiş soru, ikinci değer yeni yanıt kaydıdır.
	//
	// fromName YANITLAYANIN görünen adıdır ve kayda birlikte yazılır.
	//
	// Neden parametre? Depo katmanı kullanıcı tablosunu BİLMEZ (paket bağımlılığı
	// yönü: notify → user olmaz). Adı servis çözer. Yazılmazsa yanıt kaydı
	// kalıcı olarak adsız kalır ve arayüz "Bilinmeyen" gösterir — bu, gerçek
	// tarayıcı testinde görüldü (yanıt kartlarında gönderen "Bilinmeyen" idi).
	Answer(ctx context.Context, userID, questionID, answerText, fromName string, at time.Time) (Message, Message, error)

	// CountPending, kullanıcıya yanıt bekleyen soru sayısıdır (alıcı sınırı).
	CountPending(ctx context.Context, userID string) (int, error)

	// CountSentWindow, kullanıcının `since` anından bu yana kaç bildirim
	// gönderdiğini döndürür (gönderen saatlik sınırı).
	CountSentWindow(ctx context.Context, userID string, since time.Time) (int, error)

	// Delete kullanıcının bildirimini siler (yalnızca alıcı veya gönderen).
	Delete(ctx context.Context, userID, id string) error
}
