package storage

import (
	"context"
	"fmt"
	"github.com/jackc/pgx/v5"
	"madsky.ru/go-tracker/internal/database"
	"madsky.ru/go-tracker/internal/model/user"
)

type UserRepository interface {
	FindByEmail(ctx context.Context, email string) (*user.User, error)
	FindById(ctx context.Context, id uint32) (*user.User, error)
	Create(ctx context.Context, user *user.User) (*user.User, error)
	IsEmpty(ctx context.Context) (bool, error)
	Update(ctx context.Context, id uint32, dto *user.UpdateUserDTO) (*user.User, error)
	//Find(ctx context.Context) ([]*user.User, error)
	//FindOne(ctx context.Context, id uint64) (*user.User, error)
	//Create(ctx context.Context, dto *user.CreateUserDTO) (*user.User, error)
	//Remove(ctx context.Context, id uint64) (uint64, error)
}

type UserStore struct {
	client database.Client
}

func (us *UserStore) FindById(ctx context.Context, id uint32) (*user.User, error) {
	query := `select id, email, name, password_hash, role 
			  from users 
			  where id = $1`

	rows, _ := us.client.Query(ctx, query, id)
	defer rows.Close()

	u, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[user.User])
	if err != nil {
		fmt.Println("CollectOneRow FindById User", err)
		return nil, err
	}

	return &u, nil
}

func (us *UserStore) FindByEmail(ctx context.Context, email string) (*user.User, error) {
	query := `select id, email, name, password_hash, role 
			  from users 
			  where email = $1`

	rows, _ := us.client.Query(ctx, query, email)
	defer rows.Close()

	u, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[user.User])
	if err != nil {
		fmt.Println("CollectOneRow FindByEmail User", err)
		return nil, err
	}

	return &u, nil
}

func (us *UserStore) IsEmpty(ctx context.Context) (bool, error) {
	query := "select count(id) from users limit 1"

	rows, _ := us.client.Query(ctx, query)
	defer rows.Close()

	count, err := pgx.CollectOneRow(rows, pgx.RowTo[int])
	if err != nil {
		fmt.Println("CollectOneRow IsEmpty User", err)
		return false, err
	}

	return count == 0, nil
}

func (us *UserStore) Create(ctx context.Context, dto *user.User) (*user.User, error) {
	query := `insert into users (email, name, password_hash, role) 
			  values ($1, $2, $3, $4) 
			  returning id, name, email, password_hash, role`
	rows, _ := us.client.Query(ctx, query, dto.Email, dto.Name, dto.PasswordHash, dto.Role)
	defer rows.Close()

	u, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[user.User])
	if err != nil {
		fmt.Println("CollectOneRow Create User", err)
		return nil, err
	}

	return &u, nil
}

func (us *UserStore) Update(ctx context.Context, id uint32, dto *user.UpdateUserDTO) (*user.User, error) {
	query := `update users 
			  set name = $1 
			  where id = $2 
			  returning id, email, name, password_hash, role`

	rows, _ := us.client.Query(ctx, query, dto.Name, id)
	defer rows.Close()

	u, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[user.User])
	if err != nil {
		fmt.Println("CollectOneRow Update User", err)
		return nil, err
	}

	return &u, nil
}
