import { AuthMethod, MultiTenancyInterceptor, UseAuth } from '@backend/auth'
import {
	Body,
	Controller,
	Delete,
	Get,
	HttpCode,
	Param,
	ParseUUIDPipe,
	Patch,
	Post,
	Put,
	UseInterceptors,
} from '@nestjs/common'
import {
	ApiBadRequestResponse,
	ApiBody,
	ApiInternalServerErrorResponse,
	ApiNoContentResponse,
	ApiNotFoundResponse,
	ApiOkResponse,
	ApiTags,
} from '@nestjs/swagger'
import { CategoryService, MenuItemService } from '../services'
import {
	CategoryResponse,
	CreateCategoryRequest,
	CreateMenuItemRequest,
	ImportMenuItemRequest,
	MenuItemResponse,
	ToggleArchiveRequest,
	ToggleVisibleRequest,
	UpdateCategoryRequest,
	UpdateMenuItemRequest,
	UpdateSortOrderRequest,
} from '../types'

@UseAuth(AuthMethod.JWT)
@UseInterceptors(MultiTenancyInterceptor)
@Controller('menu')
@ApiTags('default')
export class MenuController {
	constructor(
		private readonly _categoryService: CategoryService,
		private readonly _menuItemService: MenuItemService,
	) {}

	@Get('category')
	@ApiOkResponse({ type: CategoryResponse, isArray: true })
	@ApiInternalServerErrorResponse()
	async findAllCategories(): Promise<CategoryResponse[]> {
		return this._categoryService.findAll()
	}

	@Get('category/:id')
	@ApiOkResponse({ type: CategoryResponse })
	@ApiBadRequestResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async findCategoryById(@Param('id', ParseUUIDPipe) id: string): Promise<CategoryResponse> {
		return this._categoryService.findById(id)
	}

	@Post('category')
	@ApiOkResponse({ type: CategoryResponse })
	@ApiBadRequestResponse()
	@ApiInternalServerErrorResponse()
	async createCategory(@Body() dto: CreateCategoryRequest): Promise<CategoryResponse> {
		return this._categoryService.save(dto)
	}

	@Put('category/:id')
	@ApiOkResponse({ type: CategoryResponse })
	@ApiBadRequestResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async updateCategoryById(
		@Param('id', ParseUUIDPipe) id: string,
		@Body() dto: UpdateCategoryRequest,
	): Promise<CategoryResponse> {
		return this._categoryService.updateById(id, dto)
	}

	@Delete('category/:id')
	@HttpCode(204)
	@ApiNoContentResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async deleteCategoryById(@Param('id', ParseUUIDPipe) id: string): Promise<void> {
		return this._categoryService.deleteById(id)
	}

	@Patch('category/:id/archive')
	@HttpCode(204)
	@ApiNoContentResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async toggleCategoryArchive(
		@Param('id', ParseUUIDPipe) id: string,
		@Body() { isArchived }: ToggleArchiveRequest,
	): Promise<void> {
		return this._categoryService.toggleArchive(id, isArchived)
	}

	@Patch('category/:id/visible')
	@HttpCode(204)
	@ApiNoContentResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async toggleCategoryVisible(
		@Param('id', ParseUUIDPipe) id: string,
		@Body() { isVisible }: ToggleVisibleRequest,
	): Promise<void> {
		return this._categoryService.toggleVisible(id, isVisible)
	}

	@Patch('category/sort')
	@HttpCode(204)
	@ApiBody({ type: [UpdateSortOrderRequest] })
	@ApiNoContentResponse()
	@ApiBadRequestResponse()
	@ApiInternalServerErrorResponse()
	async updateCategorySortOrder(@Body() request: UpdateSortOrderRequest[]): Promise<void> {
		return this._categoryService.updateSortOrder(request)
	}

	@Get('item')
	@ApiOkResponse({ type: MenuItemResponse, isArray: true })
	@ApiInternalServerErrorResponse()
	async findAllItem(): Promise<MenuItemResponse[]> {
		return this._menuItemService.findAll()
	}

	@Get('item/:id')
	@ApiOkResponse({ type: MenuItemResponse })
	@ApiBadRequestResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async findItemById(@Param('id', ParseUUIDPipe) id: string): Promise<MenuItemResponse> {
		return this._menuItemService.findById(id)
	}

	@Post('item')
	@ApiOkResponse({ type: MenuItemResponse })
	@ApiBadRequestResponse()
	@ApiInternalServerErrorResponse()
	async createItem(@Body() dto: CreateMenuItemRequest): Promise<MenuItemResponse> {
		return this._menuItemService.save(dto)
	}

	@Put('item/:id')
	@ApiOkResponse({ type: MenuItemResponse })
	@ApiBadRequestResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async updateItemById(
		@Param('id', ParseUUIDPipe) id: string,
		@Body() dto: UpdateMenuItemRequest,
	): Promise<MenuItemResponse> {
		return this._menuItemService.updateById(id, dto)
	}

	@Delete('item/:id')
	@HttpCode(204)
	@ApiNoContentResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async deleteItemById(@Param('id', ParseUUIDPipe) id: string): Promise<void> {
		return this._menuItemService.deleteById(id)
	}

	@Patch('item/:id/archive')
	@HttpCode(204)
	@ApiNoContentResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async toggleItemArchive(
		@Param('id', ParseUUIDPipe) id: string,
		@Body() { isArchived }: ToggleArchiveRequest,
	): Promise<void> {
		return this._menuItemService.toggleArchive(id, isArchived)
	}

	@Patch('item/:id/visible/:categoryId')
	@HttpCode(204)
	@ApiNoContentResponse()
	@ApiNotFoundResponse()
	@ApiInternalServerErrorResponse()
	async toggleItemVisible(
		@Param('id', ParseUUIDPipe) id: string,
		@Param('categoryId', ParseUUIDPipe) categoryId: string,
		@Body() { isVisible }: ToggleVisibleRequest,
	): Promise<void> {
		return this._menuItemService.toggleVisible(id, categoryId, isVisible)
	}

	@Patch('item/sort/:categoryId')
	@ApiBody({ type: [UpdateSortOrderRequest] })
	@Patch('item/sort/:categoryId')
	async updateItemSortOrder(
		@Param('categoryId', new ParseUUIDPipe()) categoryId: string,
		@Body() request: UpdateSortOrderRequest[],
	): Promise<void> {
		return this._menuItemService.updateSortOrder(request, categoryId)
	}

	@Post('import')
	@HttpCode(204)
	@ApiBody({ type: [ImportMenuItemRequest] })
	@ApiNoContentResponse()
	@ApiBadRequestResponse()
	@ApiInternalServerErrorResponse()
	async import(@Body() request: ImportMenuItemRequest[]): Promise<void> {
		return this._menuItemService.import(request)
	}
}
