package repository

import (
	"backend/pkg/notification/domain/entity"
	"context"

	"github.com/gocql/gocql"
)

type NotificationRepository interface {
	NotificationEventRepository
	UserNotificationRepository
	NotificationCursorRepository
}

// ---- 1. Event ----
// 專心管「事件本體」，fan-out 前先寫這張。
// 通常由上游 domain event consumer 呼叫 Create。

type QueryNotificationEventParam struct {
	ObjectID   *string
	ObjectType *string
	Limit      *int
}

type NotificationEventRepository interface {
	// Create 建立一筆新的 NotificationEvent。
	Create(ctx context.Context, e *entity.NotificationEvent) error
	// GetByID 依 EventID 取得事件。
	GetByID(ctx context.Context, id string) (*entity.NotificationEvent, error)
	// ListByObject 依 object_type + object_id 查詢相關事件（選用，debug / 後台用）。
	ListByObject(ctx context.Context, param QueryNotificationEventParam) ([]*entity.NotificationEvent, error)
}

// ---- 2. 使用者通知：user_notification ----
// 管使用者的小鈴鐺 row，fan-out 之後用這個寫入。

// ListLatestOptions 查列表用的參數
type ListLatestOptions struct {
	UserID  string
	Buckets []string // e.g. []string{"202511", "202510"}
	Limit   int      // 建議在 service 層限制最大值，例如 <= 100
}

type UserNotificationRepository interface {
	// CreateUserNotification 建立單一通知（針對某一個 user）。
	// 由呼叫端決定 bucket 與 TTL 秒數。
	CreateUserNotification(ctx context.Context, n *entity.UserNotification, ttlSeconds int) error

	// BulkCreate 批次建立多筆通知（fan-out worker 使用）。
	// 一般期望要嘛全部成功要嘛全部失敗。
	BulkCreate(ctx context.Context, list []*entity.UserNotification, ttlSeconds int) error

	// ListLatest 取得某 user 最新的通知列表（小鈴鐺拉下來用）。
	ListLatest(ctx context.Context, opt ListLatestOptions) ([]*entity.UserNotification, error)

	// MarkRead 將單一通知設為已讀。
	// 用 (user_id, bucket, ts) 精準定位那一筆資料。
	MarkRead(ctx context.Context, userID, bucket string, ts gocql.UUID) error

	// MarkAllRead 將指定 buckets 範圍內的通知設為已讀。
	// 常見用法：最近幾個 bucket（例如最近 30 天）全部標為已讀。
	// Cassandra 不適合全表掃描，實作時可分批 select 再 update。
	MarkAllRead(ctx context.Context, userID string, buckets []string) error

	// CountUnreadApprox 回傳未讀數（允許是近似值）。
	// 實作方式可以是：
	//   - 掃少量 buckets 中 status='UNREAD' 的 row，然後在應用端計算
	//   - 或讀取外部 counter（Redis / 另一張 counter table）
	CountUnreadApprox(ctx context.Context, userID string, buckets []string) (int64, error)
}

// ---- 3. NotificationCursorRepository ----
// 管 last_seen 光標，用來減少大量「每一筆更新已讀」的成本。

type NotificationCursorRepository interface {
	// GetCursor 取得某 user 的光標，如果不存在可以回傳 (nil, nil)。
	GetCursor(ctx context.Context, userID string) (*entity.NotificationCursor, error)
	// UpsertCursor 新增或更新光標。
	// 一般在使用者打開通知列表、或捲到最上面時更新。
	UpsertCursor(ctx context.Context, cursor *entity.NotificationCursor) error
}
