package pgdb

import (
	"context"
	"database/sql"
	"errors"
	"fmt"

	dberrors "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/database/errors"
	dbtypes "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/database/types"
	"github.com/Masterminds/squirrel"
	"github.com/lib/pq"
)

func (c *client) GetProfileById(
	ctx context.Context,
	request *dbtypes.ProfileGetRequest,
) (*dbtypes.ProfileGetResponse, error) {
	if request == nil {
		return nil, fmt.Errorf("%w: request is nil", dberrors.ErrBadRequest)
	}

	var (
		psql = squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar)

		usersTable = fmt.Sprintf("%s.%s", c.config.Schema, UsersTableName)
	)

	getProfile := psql.Select(
		"uid", "name", "phone", "email",
	).From(usersTable).
		Where(squirrel.Eq{"uid": request.Id})

	query, args, err := getProfile.ToSql()
	if err != nil {
		return nil, fmt.Errorf("%w: error building get profile query: %v", dberrors.ErrInternal, err)
	}

	row := c.db.QueryRowContext(ctx, query, args...)

	var (
		name, phoneNumber, email sql.NullString
		profile                  dbtypes.Profile
	)

	if err := row.Scan(&profile.Id, &name, &phoneNumber, &email); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, dberrors.ErrNotFound
		}

		return nil, fmt.Errorf("%w: error scanning row: %v", dberrors.ErrInternal, err)
	}

	if name.Valid {
		profile.Name = name.String
	}

	if phoneNumber.Valid {
		profile.PhoneNumber = phoneNumber.String
	}

	if email.Valid {
		profile.Email = email.String
	}

	return &dbtypes.ProfileGetResponse{
		Profile: &profile,
	}, nil
}

func (c *client) UpdateProfile(
	ctx context.Context,
	request *dbtypes.ProfileUpdateRequest,
) (*dbtypes.ProfileUpdateResponse, error) {
	if request == nil {
		return nil, fmt.Errorf("%w: request is nil", dberrors.ErrBadRequest)
	}

	if request.Name == nil && request.PhoneNumber == nil && request.Email == nil {
		return nil, fmt.Errorf("%w: nothing to update", dberrors.ErrBadRequest)
	}

	var (
		psql = squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar)

		usersTable = fmt.Sprintf("%s.%s", c.config.Schema, UsersTableName)
	)

	updateProfile := psql.Update(usersTable).
		Where(squirrel.Eq{"uid": request.Id})

	if request.Name != nil {
		updateProfile = updateProfile.Set("name", *request.Name)
	}

	if request.PhoneNumber != nil {
		updateProfile = updateProfile.Set("phone", *request.PhoneNumber)
	}

	if request.Email != nil {
		updateProfile = updateProfile.Set("email", *request.Email)
	}

	query, args, err := updateProfile.ToSql()
	if err != nil {
		return nil, fmt.Errorf("%w: error building update profile query: %v", dberrors.ErrInternal, err)
	}

	res, err := c.db.ExecContext(ctx, query, args...)
	if err != nil {
		if pqErr, ok := err.(*pq.Error); ok {
			if pqErr.Code == PGErrUniqueViolation {
				return nil, dberrors.ErrConflict
			}
		}

		return nil, fmt.Errorf("%w: error executing update profile query: %v", dberrors.ErrInternal, err)
	}

	rowsAffected, err := res.RowsAffected()
	if err != nil {
		return nil, fmt.Errorf("%w: error getting rows affected for update profile query: %v", dberrors.ErrInternal, err)
	}

	if rowsAffected == 0 {
		return nil, dberrors.ErrInternal
	}

	return &dbtypes.ProfileUpdateResponse{}, nil
}
