// Package postgres provides PostgreSQL implementations of repository interfaces.
package postgres

import (
	"context"
	"database/sql"
	"encoding/json"
	"errors"
	"time"

	"git.threesix.ai/jordan/slack5-1770603014/pkg/database"
	"git.threesix.ai/jordan/slack5-1770603014/services/preferences-api/internal/domain"
	"git.threesix.ai/jordan/slack5-1770603014/services/preferences-api/internal/port"
)

// Compile-time verification that PreferencesRepository implements port.PreferencesRepository.
var _ port.PreferencesRepository = (*PreferencesRepository)(nil)

// PreferencesRepository is a PostgreSQL implementation of port.PreferencesRepository.
type PreferencesRepository struct {
	pool *database.Pool
}

// NewPreferencesRepository creates a new PostgreSQL preferences repository.
func NewPreferencesRepository(pool *database.Pool) *PreferencesRepository {
	return &PreferencesRepository{pool: pool}
}

// Get returns preferences for a user by ID.
// Returns nil, nil if no preferences exist for the user.
func (r *PreferencesRepository) Get(ctx context.Context, userID domain.UserID) (*domain.UserPreferences, error) {
	var prefsJSON []byte
	var updatedAt time.Time

	err := r.pool.DB.QueryRowContext(ctx,
		`SELECT preferences, updated_at FROM user_preferences WHERE user_id = $1`,
		string(userID),
	).Scan(&prefsJSON, &updatedAt)

	if errors.Is(err, sql.ErrNoRows) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	var prefs domain.Preferences
	if err := json.Unmarshal(prefsJSON, &prefs); err != nil {
		return nil, err
	}

	return &domain.UserPreferences{
		UserID:      userID,
		Preferences: prefs,
		UpdatedAt:   updatedAt,
	}, nil
}

// Upsert creates or updates preferences for a user.
func (r *PreferencesRepository) Upsert(ctx context.Context, prefs *domain.UserPreferences) error {
	prefsJSON, err := json.Marshal(prefs.Preferences)
	if err != nil {
		return err
	}

	_, err = r.pool.DB.ExecContext(ctx,
		`INSERT INTO user_preferences (user_id, preferences, created_at, updated_at)
		 VALUES ($1, $2, $3, $3)
		 ON CONFLICT (user_id)
		 DO UPDATE SET preferences = $2, updated_at = $3`,
		string(prefs.UserID), prefsJSON, prefs.UpdatedAt,
	)
	return err
}
