package postgres

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

	"git.threesix.ai/jordan/slack5-1770544098/services/preferences-api/internal/domain"
)

// PreferencesRepository implements port.PreferencesRepository using PostgreSQL.
type PreferencesRepository struct {
	db *sql.DB
}

// NewPreferencesRepository creates a new PostgreSQL-backed preferences repository.
func NewPreferencesRepository(db *sql.DB) *PreferencesRepository {
	return &PreferencesRepository{db: db}
}

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

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

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	var prefs map[string]any
	if err := json.Unmarshal(prefsJSON, &prefs); err != nil {
		return nil, err
	}

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

// Upsert creates or updates preferences for a user using JSONB merge.
// Returns the full merged preferences after upsert.
func (r *PreferencesRepository) Upsert(ctx context.Context, userID string, prefs map[string]any) (*domain.UserPreferences, error) {
	prefsJSON, err := json.Marshal(prefs)
	if err != nil {
		return nil, err
	}

	var (
		resultJSON []byte
		createdAt  time.Time
		updatedAt  time.Time
	)

	err = r.db.QueryRowContext(ctx, `
		INSERT INTO user_preferences (user_id, preferences, created_at, updated_at)
		VALUES ($1, $2, NOW(), NOW())
		ON CONFLICT (user_id) DO UPDATE
		SET preferences = user_preferences.preferences || $2,
		    updated_at = NOW()
		RETURNING preferences, created_at, updated_at`,
		userID, prefsJSON,
	).Scan(&resultJSON, &createdAt, &updatedAt)

	if err != nil {
		return nil, err
	}

	var merged map[string]any
	if err := json.Unmarshal(resultJSON, &merged); err != nil {
		return nil, err
	}

	return &domain.UserPreferences{
		UserID:      userID,
		Preferences: merged,
		CreatedAt:   createdAt,
		UpdatedAt:   updatedAt,
	}, nil
}
