package postgres

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

	"github.com/google/uuid"
	"github.com/jmoiron/sqlx"

	"github.com/RyanCopley/skybridge/user/internal/domain"
	"github.com/RyanCopley/skybridge/user/internal/repository/interfaces"
)

type userProfileRepository struct {
	db *sqlx.DB
}

// NewUserProfileRepository creates a new user profile repository
func NewUserProfileRepository(db *sqlx.DB) interfaces.UserProfileRepository {
	return &userProfileRepository{db: db}
}

func (r *userProfileRepository) Create(ctx context.Context, profile *domain.UserProfile) error {
	profile.CreatedAt = time.Now()
	profile.UpdatedAt = time.Now()

	// Convert preferences to JSON
	var preferencesJSON []byte
	if profile.Preferences != nil {
		var err error
		preferencesJSON, err = json.Marshal(profile.Preferences)
		if err != nil {
			return fmt.Errorf("failed to marshal preferences: %w", err)
		}
	}

	query := `
		INSERT INTO user_profiles (
			user_id, bio, location, website, timezone, language, 
			preferences, created_at, updated_at
		) VALUES (
			$1, $2, $3, $4, $5, $6, $7, $8, $9
		)`

	_, err := r.db.ExecContext(ctx, query,
		profile.UserID, profile.Bio, profile.Location, profile.Website,
		profile.Timezone, profile.Language, preferencesJSON,
		profile.CreatedAt, profile.UpdatedAt,
	)
	if err != nil {
		return fmt.Errorf("failed to create user profile: %w", err)
	}

	return nil
}

func (r *userProfileRepository) GetByUserID(ctx context.Context, userID uuid.UUID) (*domain.UserProfile, error) {
	query := `
		SELECT user_id, bio, location, website, timezone, language,
		       preferences, created_at, updated_at
		FROM user_profiles 
		WHERE user_id = $1`

	row := r.db.QueryRowContext(ctx, query, userID)

	var profile domain.UserProfile
	var preferencesJSON sql.NullString

	err := row.Scan(
		&profile.UserID, &profile.Bio, &profile.Location, &profile.Website,
		&profile.Timezone, &profile.Language, &preferencesJSON,
		&profile.CreatedAt, &profile.UpdatedAt,
	)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, fmt.Errorf("user profile not found")
		}
		return nil, fmt.Errorf("failed to get user profile: %w", err)
	}

	// Parse preferences JSON
	if preferencesJSON.Valid && preferencesJSON.String != "" {
		var preferences map[string]interface{}
		err = json.Unmarshal([]byte(preferencesJSON.String), &preferences)
		if err != nil {
			return nil, fmt.Errorf("failed to unmarshal preferences: %w", err)
		}
		profile.Preferences = preferences
	}

	return &profile, nil
}

func (r *userProfileRepository) Update(ctx context.Context, profile *domain.UserProfile) error {
	profile.UpdatedAt = time.Now()

	// Convert preferences to JSON
	var preferencesJSON []byte
	if profile.Preferences != nil {
		var err error
		preferencesJSON, err = json.Marshal(profile.Preferences)
		if err != nil {
			return fmt.Errorf("failed to marshal preferences: %w", err)
		}
	}

	query := `
		UPDATE user_profiles SET 
			bio = $2,
			location = $3,
			website = $4,
			timezone = $5,
			language = $6,
			preferences = $7,
			updated_at = $8
		WHERE user_id = $1`

	result, err := r.db.ExecContext(ctx, query,
		profile.UserID, profile.Bio, profile.Location, profile.Website,
		profile.Timezone, profile.Language, preferencesJSON,
		profile.UpdatedAt,
	)
	if err != nil {
		return fmt.Errorf("failed to update user profile: %w", err)
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("failed to get affected rows: %w", err)
	}
	if rowsAffected == 0 {
		return fmt.Errorf("user profile not found")
	}

	return nil
}

func (r *userProfileRepository) Delete(ctx context.Context, userID uuid.UUID) error {
	query := `DELETE FROM user_profiles WHERE user_id = $1`

	result, err := r.db.ExecContext(ctx, query, userID)
	if err != nil {
		return fmt.Errorf("failed to delete user profile: %w", err)
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("failed to get affected rows: %w", err)
	}
	if rowsAffected == 0 {
		return fmt.Errorf("user profile not found")
	}

	return nil
}