import { Controller, Request, Post, Body, Get, Res, UseGuards, UseInterceptors, UploadedFile, Patch, Query, Put, Param, Delete } from "@nestjs/common"
import { ApiOperation, ApiQuery, ApiResponse, ApiTags, ApiBody, ApiConsumes, ApiBearerAuth } from "@nestjs/swagger"
import { CategoriesService } from "./categories.services"
import { toJsonResponse } from "../../common/response"

import { AdminGuard } from "../auth/guards/admin.guard"
import { CommonGuard } from "../auth/guards/common.guard"

// DTO Files
import { CreateDto } from "./dtos/create.dto"
import { ListQueryDto } from "./dtos/list-query.dto"
import { UpdateDto } from "./dtos/update.dto"
import { CategoryIdParamDto } from "./dtos/category-id-param.dto"

@ApiTags("categories")
@Controller("categories")
export class CategoriesController {
    constructor(private categoriesService: CategoriesService) { }

    // JP-
    /**
     * Create category based on request parameters.
     *
     * @Body request - An instance of CreateDto containing the category name to process of storing data.
     * @param response - The response object for sending the HTTP response.
     *
     * Responds with a 201 status if successful.
     * Logs the error and responds with the error status and message if an exception occurs.
     */
    @ApiBearerAuth("access-token")
    @ApiBody({ type: CreateDto })
    @UseGuards(AdminGuard)
    @Post()
    async create(@Body() request: CreateDto, @Request() req, @Res() response: any) {
        try {
            const data = await this.categoriesService.create(request)
            response.status(201).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }

    // JP-
    /**
     * Update category title based on request parameters.
     * @param params - An instance of CategoryIdParamDto containing the category id to process of update data.
     * @Body request - An instance of UpdateDto containing the category name to process of update data.
     * @param response - The response object for sending the HTTP response.
     *
     * Responds with a 201 status if successful.
     * Logs the error and responds with the error status and message if an exception occurs.
     */
    @ApiBearerAuth("access-token")
    @ApiBody({ type: UpdateDto })
    @UseGuards(AdminGuard)
    @Put(":category_id")
    async update(@Param() params: CategoryIdParamDto, @Body() request: UpdateDto, @Request() req, @Res() response: any) {
        try {
            const data = await this.categoriesService.update(params, request)
            response.status(201).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }

    /** JP-
     * Retrieves a list of category for admin with two languages (en as default and requested language).
     *
     * @param queryParam - Query parameters for listing category list, including pagination, sorting options, and language_code.
     * @param req - The request object, containing the authenticated user information.
     * @param response - The response object for sending the JSON response.
     *
     * Responds with a 200 status and the list of category with translations in two languages (en and requested language) if successful.
     * Logs the error and responds with the error status and message if an exception occurs.
     */
    @ApiBearerAuth("access-token")
    @ApiQuery({ name: "page", required: true, example: 1 })
    @ApiQuery({ name: "per_page", required: true, example: 50 })
    @ApiQuery({ name: "sort_by", required: false, type: "string" })
    @ApiQuery({ name: "sort", required: false, type: "string" })
    @ApiQuery({ name: "search", required: false, type: "string" })
    @ApiQuery({ name: "language_code", required: false, type: "string", description: "Language code for second translation (defaults to en). Returns en and requested language translations." })
    @UseGuards(AdminGuard)
    @Get("admin/list")
    async adminList(@Query() queryParam: ListQueryDto, @Request() req, @Res() response: any) {
        try {
            const data = await this.categoriesService.adminList(queryParam)
            response.status(200).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }

    /** JP-
     * Retrieves a list of category on query parameters.
     *
     * @param queryParam - Query parameters for listing category list, including pagination and sorting options.
     * @param req - The request object, containing the authenticated user information.
     * @param response - The response object for sending the JSON response.
     *
     * Responds with a 200 status and the list of category if successful.
     * Logs the error and responds with the error status and message if an exception occurs.
     */
    @ApiQuery({ name: "page", required: true, example: 1 })
    @ApiQuery({ name: "per_page", required: true, example: 50 })
    @ApiQuery({ name: "sort_by", required: false, type: "string" })
    @ApiQuery({ name: "sort", required: false, type: "string" })
    @ApiQuery({ name: "search", required: false, type: "string" })
    @UseGuards(CommonGuard)
    @Get()
    async list(@Query() queryParam: ListQueryDto, @Request() req, @Res() response: any) {
        try {
            const data = await this.categoriesService.list(queryParam, req.user)
            response.status(200).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }

    @UseGuards(CommonGuard)
    @Get('keyword-json')
    async categoryKeywordJson(@Request() req, @Res() response: any) {
        try {
            const data = await this.categoriesService.categoryKeywordJson(req.user)
            response.status(200).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }

    @Get('influencer/:slug')
    async categoryInfluencer(@Param() param: any, @Query() query: any, @Res() response: any) {
        try {
            const data = await this.categoriesService.categoryInfluencer(param, query)
            response.status(200).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status || 500).json(toJsonResponse(error.status || 500, error.message))
        }
    }

    /** JP-
     * Get category details by ID.
     * @param params - An instance of CategoryIdParamDto containing the category id.
     * @param query - Query parameters including optional language_code.
     * @param req - The request object, containing the authenticated user information.
     * @param response - The response object for sending the HTTP response.
     *
     * Responds with a 200 status and the category details if successful.
     * Logs the error and responds with the error status and message if an exception occurs.
     */
    @ApiQuery({ name: "language_code", required: false, type: "string", description: "Language code for translations (defaults to en)" })
    @UseGuards(CommonGuard)
    @Get(":category_id")
    async detail(@Param() params: CategoryIdParamDto, @Request() req, @Res() response: any) {

        const data = await this.categoriesService.detail(params, req.user)
        response.status(200).json(data)

    }

    /** JP-
     * Update category activation status based on request parameters.
     * @param params - An instance of CategoryIdParamDto containing the category id to process of update data.
     * The request, if category activation status is active than its inactive or if category activation status is inactive then its make active.
     * @param response - The response object for sending the HTTP response.
     * Responds with a 201 status and the category activation status update if successful.
     * Logs the error and responds with the error status and message if an exception occurs.
     */
    @UseGuards(AdminGuard)
    @Patch("activation-status/:category_id")
    async activationStatusUpdate(@Param() params: CategoryIdParamDto, @Request() req, @Res() response: any) {
        try {
            await this.categoriesService.activationStatusUpdate(params)
            response.status(201).json()
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }

    /** JP-
     * Toggle category recommended status (recommended ↔ not recommended).
     * @param params - Category id from route params.
     * @param response - HTTP response object.
     * Responds with 201 on success; error status and message on failure.
     */
    @ApiBearerAuth("access-token")
    @UseGuards(AdminGuard)
    @Patch("recommended-status/:category_id")
    async recommendedStatusUpdate(@Param() params: CategoryIdParamDto, @Request() req, @Res() response: any) {
        try {
            await this.categoriesService.recommendedStatusUpdate(params)
            response.status(201).json()
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }

    @ApiBearerAuth("access-token")
    @UseGuards(AdminGuard)
    @Get(":category_id/influencer-count")
    async influencerCount(@Param() params: CategoryIdParamDto, @Res() response: any) {
        try {
            const data = await this.categoriesService.influencerCount(params)
            response.status(200).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status || 500).json(toJsonResponse(error.status || 500, error.message))
        }
    }

    @Delete(":category_id")
    async delete(@Param() params: CategoryIdParamDto, @Request() req, @Res() response: any) {
        try {
            await this.categoriesService.delete(params)
            response.status(201).json()
        } catch (error) {
            console.log(error)
            response.status(400).json(toJsonResponse(error.status, error.message))
        }
    }
}
