package user

import (
	"database/sql"

	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/storage/dao"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/storage/dao/postgresql"

	"github.com/lib/pq"
)

type Database struct {
	*postgresql.DatabasePostgreSQL
}

func NewDatabase(db *postgresql.DatabasePostgreSQL) *Database {
	return &Database{db}
}

func (db *Database) GetAllUsers() ([]*User, error) {
	q := `
		SELECT u.id, u.created_at, u.updated_at, u.email
		FROM public.user u
	`
	rows, err := db.Session.Query(q)
	if err != nil {
		return nil, err
	}
	defer func(rows *sql.Rows) {
		err := rows.Close()
		if err != nil {
			return
		}
	}(rows)

	us := make([]*User, 0)
	for rows.Next() {
		u := User{}
		err := rows.Scan(&u.ID, &u.CreatedAt, &u.UpdatedAt, &u.Email)
		if err != nil {
			return nil, err
		}
		us = append(us, &u)
	}
	return us, nil
}

func (db *Database) GetUsersByID(id string) (*User, error) {
	q := `
		SELECT u.id, u.created_at, u.updated_at, u.email
		FROM public.user u
		WHERE u.id = $1
	`
	row := db.Session.QueryRow(q, id)

	u := User{}
	err := row.Scan(&u.ID, &u.CreatedAt, &u.UpdatedAt, &u.Email)
	if errPq, ok := err.(*pq.Error); ok {
		return nil, postgresql.HandlePgError(errPq)
	}
	if err == sql.ErrNoRows {
		return nil, dao.NewDAOError(dao.ErrTypeNotFound, err)
	}
	return &u, err
}

func (db *Database) CreateUser(user *User) error {
	q := `
		INSERT INTO public.user
			(email, google_id)
		VALUES
			($1, $2)
		RETURNING id, created_at
	`

	err := db.Session.
		QueryRow(q, user.Email, user.GoogleID).
		Scan(&user.ID, &user.CreatedAt)
	if errPq, ok := err.(*pq.Error); ok {
		return postgresql.HandlePgError(errPq)
	}
	return err
}

func (db *Database) DeleteUser(id string) error {
	q := `
		DELETE FROM public.user
		WHERE id = $1
	`

	_, err := db.Session.Exec(q, id)
	if errPq, ok := err.(*pq.Error); ok {
		return postgresql.HandlePgError(errPq)
	}
	return err
}

func (db *Database) UpdateUser(user *User) error {
	return nil
}

func (db *Database) GetUsersByGoogleID(id string) (*User, error) {
	q := `
		SELECT u.id, u.created_at, u.updated_at, u.email, u.google_id
		FROM public.user u
		WHERE u.google_id = $1
	`
	row := db.Session.QueryRow(q, id)

	u := User{}
	err := row.Scan(&u.ID, &u.CreatedAt, &u.UpdatedAt, &u.Email, &u.GoogleID)
	if errPq, ok := err.(*pq.Error); ok {
		return nil, postgresql.HandlePgError(errPq)
	}
	if err == sql.ErrNoRows {
		return nil, dao.NewDAOError(dao.ErrTypeNotFound, err)
	}
	return &u, err
}
