import type { HttpContext } from '@adonisjs/core/http'
import RestaurantMenuItem from '#models/restaurant_menu_item'
import RestaurantMenu from '#models/restaurant_menu'
import logger from '@adonisjs/core/services/logger'
import { menuItemValidator } from '#validators/menu'

export default class RestaurantMenuItemsController {
  /**
   * Retrieve all restaurant menu items.
   *
   * @returns An array of all restaurant menu items.
   */
  async getAll() {
    const items = await RestaurantMenuItem.query().preload('category').preload('menus')
    return items
  }

  /**
   * Retrieve a single restaurant menu item.
   *
   * @param request - The HTTP context containing the request data.
   * @returns The restaurant menu item with the specified id.
   */

  async getOne({ request }: HttpContext) {
    try {
      const id = request.body().id
      const item = await RestaurantMenuItem.query()
        .where('id', id)
        .preload('category')
        .preload('menus')
        .first()
      return item
    } catch (error) {
      logger.error('Menu item retrieval failed: %s', error)
    }
  }

  // The following methods require authentication. Log user activity.

  /**
   * Create a restaurant menu item.
   *
   * @bodyParam *name* -  string | The name of the menu item.
   * @bodyParam *priceSmall* -  number | The price of the small serving of the menu item.
   * @bodyParam *priceLarge* -  number | The price of the large serving of the menu item.
   * @bodyParam *description* -  string | The description of the menu item.
   * @bodyParam *menu_id* -  number | The menu id of the menu item.
   * @returns The created menu item.
   */
  async create({ request, auth }: HttpContext) {
    const data = await request.validateUsing(menuItemValidator)
    try {
      const item = await RestaurantMenuItem.create(data)
      logger.info('Menu item created: %s by %s', item.name, auth.getUserOrFail().email)
      return item
    } catch (error) {
      logger.error('Menu item creation failed: %s', error)
    }
  }

  /**
   * Update a restaurant menu item.
   *
   * @bodyParam *id* -  number | The id of the menu item to update.
   * @bodyParam *name* -  string | The new name of the menu item.
   * @bodyParam *priceSmall* -  number | The new price of the small size of the menu item.
   * @bodyParam *priceLarge* -  number | The new price of the large size of the menu item.
   * @bodyParam *description* -  string | The new description of the menu item.
   * @bodyParam *menu_id* -  number | The new menu id of the menu item.
   */
  async update({ request, auth }: HttpContext) {
    const data = request.body()
    try {
      const item = await RestaurantMenuItem.find(data.id)
      item?.merge(data)
      await item?.save()
      logger.info('Menu item updated: %s by %s', item?.name, auth.getUserOrFail().email)
    } catch (error) {
      logger.error('Menu item update failed: %s', error)
    }
  }

  /**
   * Delete a restaurant menu item.
   *
   * @bodyParam *id* - number | The id of the menu item to delete.
   */
  async delete({ request, auth, response }: HttpContext) {
    const id = request.body().id
    try {
      const item = await RestaurantMenuItem.find(id)
      if (!item) {
        return response.notFound({ message: 'Menu item not found' })
      }
      // Detach from all menus first
      await item.related('menus').detach()
      await item.delete()
      logger.info('Menu item deleted: %s by %s', item.name, auth.getUserOrFail().email)
      return response.ok({ message: 'Menu item deleted' })
    } catch (error) {
      logger.error('Menu item deletion failed: %s', error)
      return response.internalServerError({ message: 'Menu item deletion failed' })
    }
  }

  // This method connects the menu item to a menu.

  /**
   * Connect a restaurant menu item to a restaurant menu.
   *
   * @bodyParam *item_id* - number | The id of the menu item to connect.
   * @bodyParam *menu_id* - number | The id of the menu to connect the menu item to.
   */
  async connectToMenu({ request, response }: HttpContext) {
    const data = request.body()
    try {
      const item = await RestaurantMenuItem.find(data.item_id)
      const menu = await RestaurantMenu.find(data.menu_id)

      if (!item || !menu) {
        return response.notFound({ message: 'Menu or Item not found' })
      }

      await item.related('menus').attach([menu.id])
      return response.ok({ message: 'Menu item connected to menu' })
    } catch (error) {
      logger.error('Menu item connection failed: %s', error)
      return response.internalServerError({ message: 'Menu item connection failed' })
    }
  }
}
