package dao

import (
	"context"
	"daoplugin/entity"
	"database/sql"
	"fmt"
	"strings"

	"golang.org/x/xerrors"
)

type Field interface {
	Count(context.Context) (int64, error)
	FindAll(context.Context) (entity.Fields, error)
	FindByDifficulties(context.Context, []int) (entity.Fields, error)
	FindByDifficulty(context.Context, int) (entity.Fields, error)
	FindByDifficultyAndLevel(context.Context, int, int) (entity.Fields, error)
	FindByID(context.Context, uint64) (*entity.Field, error)
	FindByIDs(context.Context, []uint64) (entity.Fields, error)
	FindByLocationX(context.Context, int) (entity.Fields, error)
	FindByLocationXAndLocationY(context.Context, int, int) (*entity.Field, error)
	FindByLocationXes(context.Context, []int) (entity.Fields, error)
	FindByName(context.Context, string) (*entity.Field, error)
	FindByNames(context.Context, []string) (entity.Fields, error)
	FindByObjectNum(context.Context, int) (entity.Fields, error)
	FindByObjectNums(context.Context, []int) (entity.Fields, error)
}

type FieldImpl struct {
	tx *sql.Tx
}

func NewField(ctx context.Context, tx *sql.Tx) Field {
	return &FieldImpl{tx: tx}
}

// generated by eevee
func (d *FieldImpl) Count(ctx context.Context) (r int64, e error) {
	var value int64
	query := "COUNT(*) FROM `fields`"
	if err := d.tx.QueryRowContext(ctx, query).Scan(&value); err != nil {
		if err == sql.ErrNoRows {
			return 0, nil
		}
		return 0, xerrors.Errorf("failure query %s: %w", query, err)
	}
	return value, nil
}

// generated by eevee
func (d *FieldImpl) FindAll(ctx context.Context) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields`"
	rows, err := d.tx.QueryContext(ctx, query)
	if err != nil {
		return values, xerrors.Errorf("falure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(&value.ID, &value.Name, &value.LocationX, &value.LocationY, &value.ObjectNum, &value.Level, &value.Difficulty); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByDifficulties(ctx context.Context, a0 []int) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `difficulty` IN (%s)"
	args := []interface{}{}
	placeholders := make([]string, 0, len(a0))
	for _, v := range a0 {
		args = append(args, v)
		placeholders = append(placeholders, "?")
	}
	selectQuery := fmt.Sprintf(query, strings.Join(placeholders, ", "))
	rows, err := d.tx.QueryContext(ctx, selectQuery, args...)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByDifficulty(ctx context.Context, a0 int) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `difficulty` = ?"
	rows, err := d.tx.QueryContext(ctx, query, a0)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByDifficultyAndLevel(ctx context.Context, a0 int, a1 int) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `difficulty` = ? AND `level` = ?"
	rows, err := d.tx.QueryContext(ctx, query, a0, a1)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByID(ctx context.Context, a0 uint64) (r *entity.Field, e error) {
	var value entity.Field
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `id` = ?"
	if err := d.tx.QueryRowContext(ctx, query, a0).Scan(
		&value.ID,
		&value.Name,
		&value.LocationX,
		&value.LocationY,
		&value.ObjectNum,
		&value.Level,
		&value.Difficulty,
	); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, xerrors.Errorf("failure query %s: %w", query, err)
	}
	return &value, nil
}

// generated by eevee
func (d *FieldImpl) FindByIDs(ctx context.Context, a0 []uint64) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `id` IN (%s)"
	args := []interface{}{}
	placeholders := make([]string, 0, len(a0))
	for _, v := range a0 {
		args = append(args, v)
		placeholders = append(placeholders, "?")
	}
	selectQuery := fmt.Sprintf(query, strings.Join(placeholders, ", "))
	rows, err := d.tx.QueryContext(ctx, selectQuery, args...)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByLocationX(ctx context.Context, a0 int) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `location_x` = ?"
	rows, err := d.tx.QueryContext(ctx, query, a0)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByLocationXAndLocationY(ctx context.Context, a0 int, a1 int) (r *entity.Field, e error) {
	var value entity.Field
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `location_x` = ? AND `location_y` = ?"
	if err := d.tx.QueryRowContext(ctx, query, a0, a1).Scan(
		&value.ID,
		&value.Name,
		&value.LocationX,
		&value.LocationY,
		&value.ObjectNum,
		&value.Level,
		&value.Difficulty,
	); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, xerrors.Errorf("failure query %s: %w", query, err)
	}
	return &value, nil
}

// generated by eevee
func (d *FieldImpl) FindByLocationXes(ctx context.Context, a0 []int) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `location_x` IN (%s)"
	args := []interface{}{}
	placeholders := make([]string, 0, len(a0))
	for _, v := range a0 {
		args = append(args, v)
		placeholders = append(placeholders, "?")
	}
	selectQuery := fmt.Sprintf(query, strings.Join(placeholders, ", "))
	rows, err := d.tx.QueryContext(ctx, selectQuery, args...)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByName(ctx context.Context, a0 string) (r *entity.Field, e error) {
	var value entity.Field
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `name` = ?"
	if err := d.tx.QueryRowContext(ctx, query, a0).Scan(
		&value.ID,
		&value.Name,
		&value.LocationX,
		&value.LocationY,
		&value.ObjectNum,
		&value.Level,
		&value.Difficulty,
	); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, xerrors.Errorf("failure query %s: %w", query, err)
	}
	return &value, nil
}

// generated by eevee
func (d *FieldImpl) FindByNames(ctx context.Context, a0 []string) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `name` IN (%s)"
	args := []interface{}{}
	placeholders := make([]string, 0, len(a0))
	for _, v := range a0 {
		args = append(args, v)
		placeholders = append(placeholders, "?")
	}
	selectQuery := fmt.Sprintf(query, strings.Join(placeholders, ", "))
	rows, err := d.tx.QueryContext(ctx, selectQuery, args...)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByObjectNum(ctx context.Context, a0 int) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `object_num` = ?"
	rows, err := d.tx.QueryContext(ctx, query, a0)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}

// generated by eevee
func (d *FieldImpl) FindByObjectNums(ctx context.Context, a0 []int) (r entity.Fields, e error) {
	values := entity.Fields{}
	query := "SELECT `id`, `name`, `location_x`, `location_y`, `object_num`, `level`, `difficulty` FROM `fields` WHERE `object_num` IN (%s)"
	args := []interface{}{}
	placeholders := make([]string, 0, len(a0))
	for _, v := range a0 {
		args = append(args, v)
		placeholders = append(placeholders, "?")
	}
	selectQuery := fmt.Sprintf(query, strings.Join(placeholders, ", "))
	rows, err := d.tx.QueryContext(ctx, selectQuery, args...)
	if err != nil {
		return values, xerrors.Errorf("failure query %s: %w", query, err)
	}
	defer func() {
		if err := rows.Close(); err != nil {
			e = xerrors.Errorf("cannot close rows: %w", err)
		}
	}()
	for rows.Next() {
		var value entity.Field
		if err := rows.Scan(
			&value.ID,
			&value.Name,
			&value.LocationX,
			&value.LocationY,
			&value.ObjectNum,
			&value.Level,
			&value.Difficulty,
		); err != nil {
			return values, xerrors.Errorf("cannot scan value: %w", err)
		}
		values = append(values, &value)
	}
	return values, nil
}
