package mysql

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

	"git.gocasts.ir/ebhomengo/niki/domain/account/entity"
	"git.gocasts.ir/ebhomengo/niki/pkg/database/mysql"
	errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
	richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
	types "git.gocasts.ir/ebhomengo/niki/pkg/types"
)

const (
	StatementKeyIsExistDriverByPhoneNumber = iota + 1
	StatementKeyCreateDriver               = iota + 1
)

type AccountRepo struct {
	db *mysql.DB
}

func New(db *mysql.DB) AccountRepo {
	return AccountRepo{
		db: db,
	}
}

func (r AccountRepo) IsExistDriverByPhoneNumber(ctx context.Context, phoneNumber string) (bool, entity.Driver, error) {
	const op = "Repository.IsExistDriverByPhoneNumber"
	query := `select * from drivers where phone_number = ?`
	stmt, err := r.db.PrepareStatement(ctx, StatementKeyIsExistDriverByPhoneNumber, query)
	if err != nil {
		return false, entity.Driver{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected).
			WithMessage(errmsg.ErrorMsgCantPrepareStatement)
	}

	defer stmt.Close()

	row := stmt.QueryRowContext(ctx, phoneNumber)
	d, sErr := DriverScan(row)
	if sErr != nil {
		if errors.Is(sErr, sql.ErrNoRows) {
			return false, entity.Driver{}, richerror.New(op).WithKind(richerror.KindNotFound).
				WithMessage(errmsg.ErrorMsgNotFound)
		}
		return false, entity.Driver{}, richerror.New(op).WithErr(err).
			WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
	}

	return true, d, nil

}

func (r AccountRepo) CreateDriver(ctx context.Context, driver entity.Driver) (entity.Driver, error) {
	const op = "Repository.CreateDriver"
	query := `insert into drivers(phone_number) values(?)`

	stmt, err := r.db.PrepareStatement(ctx, StatementKeyCreateDriver, query)
	if err != nil {
		return entity.Driver{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected).
			WithMessage(errmsg.ErrorMsgCantPrepareStatement)
	}

	res, err := stmt.ExecContext(ctx, driver.PhoneNumber)

	if err != nil {
		return entity.Driver{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected).
			WithMessage(errmsg.ErrorMsgNotFound)
	}

	id, _ := res.LastInsertId()
	driver.ID = types.ID(id)

	return driver, nil
}

func DriverScan(scanner mysql.Scanner) (entity.Driver, error) {
	var createdAt, updatedAt time.Time
	var driver entity.Driver

	err := scanner.Scan(&driver.ID, &driver.PhoneNumber, &createdAt, &updatedAt)

	return driver, err
}
