package postgres

import (
	"context"
	"errors"
	"fmt"

	"github.com/jackc/pgx/v5"
)

type User struct {
	ID        string
	PublicID  string
	Status    string
	Nickname  *string
	AvatarURL *string
}

type CreateUserParams struct {
	PublicID string
	Status   string
}

type queryRower interface {
	QueryRow(context.Context, string, ...any) pgx.Row
}

func (s *Store) FindUserByMobile(ctx context.Context, tx Tx, countryCode, mobile string) (*User, error) {
	row := tx.QueryRow(ctx, `
		SELECT u.id, u.user_public_id, u.status, u.nickname, u.avatar_url
		FROM users u
		JOIN login_identities li ON li.user_id = u.id
		WHERE li.provider = 'mobile'
		  AND li.country_code = $1
		  AND li.mobile = $2
		  AND li.status = 'active'
		LIMIT 1
	`, countryCode, mobile)
	return scanUser(row)
}

func (s *Store) CreateUser(ctx context.Context, tx Tx, params CreateUserParams) (*User, error) {
	row := tx.QueryRow(ctx, `
		INSERT INTO users (user_public_id, status)
		VALUES ($1, $2)
		RETURNING id, user_public_id, status, nickname, avatar_url
	`, params.PublicID, params.Status)
	return scanUser(row)
}

func (s *Store) TouchUserLogin(ctx context.Context, tx Tx, userID string) error {
	_, err := tx.Exec(ctx, `
		UPDATE users
		SET last_login_at = NOW()
		WHERE id = $1
	`, userID)
	if err != nil {
		return fmt.Errorf("touch user last login: %w", err)
	}
	return nil
}

func (s *Store) DeactivateUser(ctx context.Context, tx Tx, userID string) error {
	_, err := tx.Exec(ctx, `
		UPDATE users
		SET status = 'deleted', updated_at = NOW()
		WHERE id = $1
	`, userID)
	if err != nil {
		return fmt.Errorf("deactivate user: %w", err)
	}
	return nil
}

func (s *Store) GetUserByID(ctx context.Context, db queryRower, userID string) (*User, error) {
	row := db.QueryRow(ctx, `
		SELECT id, user_public_id, status, nickname, avatar_url
		FROM users
		WHERE id = $1
	`, userID)
	return scanUser(row)
}

func scanUser(row pgx.Row) (*User, error) {
	var user User
	err := row.Scan(&user.ID, &user.PublicID, &user.Status, &user.Nickname, &user.AvatarURL)
	if errors.Is(err, pgx.ErrNoRows) {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("scan user: %w", err)
	}
	return &user, nil
}
