package adminnotification

import (
	"context"

	"hfb_sys/backend/internal/model"

	"gorm.io/gorm"
)

type Repository struct {
	db *gorm.DB
}

func NewRepository(db *gorm.DB) *Repository {
	return &Repository{db: db}
}

func (r *Repository) List(ctx context.Context, query Query) (*PaginatedResult, error) {
	db := r.db.WithContext(ctx).Model(&model.AdminNotification{}).
		Where("admin_user_id = ?", query.AdminUserID)
	countDB := r.db.WithContext(ctx).Model(&model.AdminNotification{}).
		Where("admin_user_id = ?", query.AdminUserID)
	if query.OnlyUnread {
		db = db.Where("is_read = ?", false)
		countDB = countDB.Where("is_read = ?", false)
	}

	var total int64
	if err := countDB.Count(&total).Error; err != nil {
		return nil, err
	}

	offset := (query.Page - 1) * query.PageSize
	var rows []model.AdminNotification
	if err := db.Order("id DESC").Offset(offset).Limit(query.PageSize).Find(&rows).Error; err != nil {
		return nil, err
	}
	items := make([]NotificationDTO, 0, len(rows))
	for _, row := range rows {
		items = append(items, toDTO(row))
	}
	return &PaginatedResult{Items: items, Total: total, Page: query.Page, PageSize: query.PageSize}, nil
}

func (r *Repository) UnreadCount(ctx context.Context, adminUserID uint64) (int64, error) {
	var total int64
	err := r.db.WithContext(ctx).Model(&model.AdminNotification{}).
		Where("admin_user_id = ? AND is_read = ?", adminUserID, false).
		Count(&total).Error
	return total, err
}

func (r *Repository) MarkRead(ctx context.Context, adminUserID uint64, id uint64) error {
	result := r.db.WithContext(ctx).Model(&model.AdminNotification{}).
		Where("id = ? AND admin_user_id = ?", id, adminUserID).
		Update("is_read", true)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		var total int64
		if err := r.db.WithContext(ctx).Model(&model.AdminNotification{}).
			Where("id = ? AND admin_user_id = ?", id, adminUserID).
			Count(&total).Error; err != nil {
			return err
		}
		if total == 0 {
			return ErrNotificationNotFound
		}
	}
	return nil
}

func (r *Repository) MarkAllRead(ctx context.Context, adminUserID uint64) (int64, error) {
	result := r.db.WithContext(ctx).Model(&model.AdminNotification{}).
		Where("admin_user_id = ? AND is_read = ?", adminUserID, false).
		Update("is_read", true)
	return result.RowsAffected, result.Error
}

// Entry 描述一条待写入的管理员通知。
type Entry struct {
	AdminUserID uint64
	Type        string
	Title       string
	Content     string
}

// Append 在事务中批量写入管理员通知。
// 典型用法：在业务事务内调用 adminnotification.Append(tx, entries...)，
// 确保通知与业务数据在同一事务中提交或回滚。
func Append(tx *gorm.DB, entries ...Entry) error {
	for _, entry := range entries {
		if entry.AdminUserID == 0 || entry.Title == "" {
			continue
		}
		row := model.AdminNotification{
			AdminUserID: entry.AdminUserID,
			Type:        entry.Type,
			Title:       entry.Title,
			Content:     entry.Content,
		}
		if row.Type == "" {
			row.Type = "system"
		}
		if err := tx.Create(&row).Error; err != nil {
			return err
		}
	}
	return nil
}

func toDTO(row model.AdminNotification) NotificationDTO {
	return NotificationDTO{
		ID:          row.ID,
		AdminUserID: row.AdminUserID,
		Type:        row.Type,
		Title:       row.Title,
		Content:     row.Content,
		IsRead:      row.IsRead,
		CreatedAt:   row.CreatedAt,
		UpdatedAt:   row.UpdatedAt,
	}
}
