package journal

import (
	"context"
	"errors"
	"fmt"
	"html"

	"gorm.io/gorm"
)

type Repository struct {
	db *gorm.DB
}

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

func (r *Repository) Create(ctx context.Context, entry *Entry) error {
	if entry == nil {
		return fmt.Errorf("entry cannot be nil")
	}

	sanitizedContent := sanitizeContent(entry.Content)
	entry.Content = sanitizedContent

	err := r.db.WithContext(ctx).Create(entry).Error
	if err != nil {
		return fmt.Errorf("failed to create entry: %w", err)
	}

	return nil
}

func (r *Repository) FindByID(ctx context.Context, id int) (*Entry, error) {
	var entry Entry
	err := r.db.WithContext(ctx).Where("id = ?", id).First(&entry).Error
	if err != nil {
		return nil, fmt.Errorf("failed to find entry: %w", err)
	}

	return &entry, nil
}

func (r *Repository) Find(ctx context.Context, limit int, offsetID *int) ([]*Entry, error) {
	var entries []*Entry

	if offsetID == nil {
		err := r.db.WithContext(ctx).Limit(limit).Order("date DESC, id DESC").Find(&entries).Error
		if err != nil {
			return nil, errors.Join(errors.New("failed to find entries"), err)
		}

		return entries, nil
	}

	if *offsetID < 0 {
		return nil, fmt.Errorf("offsetID must be greater than or equal to 0, %d given", *offsetID)
	}

	if limit <= 0 {
		return nil, fmt.Errorf("limit must be greater than 0")
	}

	err := r.db.WithContext(ctx).Where("id > ?", offsetID).Limit(limit).Order("id ASC").Find(&entries).Error
	if err != nil {
		return nil, fmt.Errorf("failed to find entries: %w", err)
	}

	return entries, nil
}

func (r *Repository) Update(ctx context.Context, entry *Entry) error {
	if entry == nil {
		return fmt.Errorf("entry cannot be nil")
	}

	sanitizedContent := sanitizeContent(entry.Content)
	entry.Content = sanitizedContent

	err := r.db.WithContext(ctx).Save(entry).Error
	if err != nil {
		return fmt.Errorf("failed to update entry: %w", err)
	}

	return nil
}

func (r *Repository) Delete(ctx context.Context, id int) error {
	err := r.db.WithContext(ctx).Delete(&Entry{}, id).Error
	if err != nil {
		return fmt.Errorf("failed to delete entry: %w", err)
	}

	return nil
}

func sanitizeContent(content string) string {
	// Implement your sanitization logic here
	// For example, you can use a library like "github.com/microcosm-cc/bluemonday" to sanitize HTML content
	return html.EscapeString(content)
}
