package controllers

import (
	"database/sql"
	"errors"
	"github.com/jmoiron/sqlx"
	"go_project/internal/models"
	"log"
)

type (
	ListTableParams struct {
		Limit  int `db:"limit" json:"limit"`
		Offset int `db:"offset" json:"offset"`
	}

	CreateTableParams struct {
		Name      int    `db:"name" json:"name"`
		MaxPeople int    `db:"max_people" json:"max_people"`
		Room      string `db:"room" json:"room"`
	}

	UpdateTableParams struct {
		Id        int    `db:"id" json:"id"`
		Name      int    `db:"name" json:"name"`
		MaxPeople int    `db:"max_people" json:"max_people"`
		Room      string `db:"room" json:"room"`
	}
)

func TableById(db *sqlx.DB, id int) (*models.Table, error) {
	rows, err := db.Query("SELECT * FROM Tables WHERE id = ?", id)

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	if isEmpty := !rows.Next(); isEmpty {
		return nil, nil
	}

	result := new(models.Table)
	err = rows.Scan(&result.Id, &result.Name, &result.MaxPeople, &result.Room)

	return result, err
}

func AllTables(db *sqlx.DB, params ListTableParams) ([]models.Table, error) {
	query := `SELECT * FROM Tables ORDER BY id LIMIT $1 OFFSET $2`

	rows, err := db.Query(query, params.Limit, params.Offset)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var result []models.Table
	for rows.Next() {
		var currentTable models.Table

		err = rows.Scan(&currentTable.Id, &currentTable.Name, &currentTable.MaxPeople, &currentTable.Room)

		if err != nil {
			return nil, err
		}

		result = append(result, currentTable)
	}
	return result, err
}

func CreateTable(db *sqlx.DB, params CreateTableParams) (*models.Table, error) {
	query := `
		INSERT INTO Tables (name, max_people, room)
		VALUES (?, ?, ?)
		RETURNING id, name, max_people, room
	`

	var table models.Table

	err := db.QueryRow(query, params.Name, params.MaxPeople, params.Room).Scan(
		&table.Id,
		&table.Name,
		&table.MaxPeople,
		&table.Room,
	)
	if err != nil {
		log.Printf("CreateTable: Insertion operation of the Tables object is failed: %v\n", err)
		return nil, err
	}

	log.Println("CreateTable: Insertion operation of the Tables object is successful")
	return &table, nil
}

func DeleteTableById(db *sqlx.DB, id int) (sql.Result, error) {
	sqlResult, err := db.Exec("DELETE FROM Tables WHERE id = ?", id)

	if err == nil {
		log.Println("DeleteTableById: Deletion operation of the Tables object is successful")
	}

	return sqlResult, err
}

func UpdateTable(db *sqlx.DB, params UpdateTableParams) (*models.Table, error) {
	query := `
		UPDATE Tables 
		SET name = $1, max_people = $2, room = $3 
		WHERE id = $4 
		RETURNING id, name, max_people, room
	`

	result := &models.Table{}
	err := db.QueryRow(query, params.Name, params.MaxPeople, params.Room, params.Id).
		Scan(&result.Id, &result.Name, &result.MaxPeople, &result.Room)
	if err != nil {
		switch {
		case errors.Is(err, sql.ErrNoRows):
			log.Printf("No rows affected for Table ID %d", params.Id)
			return nil, errors.New("no rows affected: update failed")
		default:
			log.Printf("Query execution error for Table ID %d: %v", params.Id, err)
			return nil, err
		}
	}

	log.Printf("Table ID %d updated successfully", result.Id)
	return result, nil
}
