import {
  Get,
  Post,
  Put,
  Delete,
  Param,
  Query,
  Body,
  HttpCode,
  ParseUUIDPipe,
} from '@nestjs/common';
import {
  ApiOperation,
  ApiOkResponse,
  ApiNotFoundResponse,
  ApiBadRequestResponse,
} from '@nestjs/swagger';
import { BaseService } from './base.service';
import { PaginationDto } from '../dto/pagination.dto';
import {
  ApiResponse,
  createSuccessResponse,
  createPaginatedResponse,
} from '../types/api-response.type';

/**
 * Generic base controller with common CRUD endpoints
 * Extend this class for entity-specific controllers
 *
 * Note: Use decorators like @Controller() on the child class
 */
export abstract class BaseController<T, CreateDto, UpdateDto> {
  constructor(
    protected readonly service: BaseService<T, CreateDto, UpdateDto>,
    protected readonly entityName: string,
  ) {}

  @Get()
  @HttpCode(200)
  @ApiOperation({ summary: 'Get all records with pagination' })
  @ApiOkResponse({ description: 'Records retrieved successfully' })
  async findAll(
    @Query() pagination: PaginationDto,
  ): Promise<ApiResponse<{ items: T[]; meta: any }>> {
    const result = await this.service.findAll(pagination);
    return createPaginatedResponse(
      result.items,
      result.meta.total,
      result.meta.page,
      result.meta.limit,
      `${this.entityName} list retrieved successfully`,
    );
  }

  @Get(':id')
  @HttpCode(200)
  @ApiOperation({ summary: 'Get a record by ID' })
  @ApiOkResponse({ description: 'Record retrieved successfully' })
  @ApiNotFoundResponse({ description: 'Record not found' })
  async findOne(
    @Param('id', ParseUUIDPipe) id: string,
  ): Promise<ApiResponse<T>> {
    const result = await this.service.findOne(id);
    return createSuccessResponse(
      result,
      `${this.entityName} retrieved successfully`,
    );
  }

  @Post()
  @HttpCode(200)
  @ApiOperation({ summary: 'Create a new record' })
  @ApiOkResponse({ description: 'Record created successfully' })
  @ApiBadRequestResponse({ description: 'Validation failed' })
  async create(@Body() createDto: CreateDto): Promise<ApiResponse<T>> {
    const result = await this.service.create(createDto);
    return createSuccessResponse(
      result,
      `${this.entityName} created successfully`,
      201,
    );
  }

  @Put(':id')
  @HttpCode(200)
  @ApiOperation({ summary: 'Update an existing record' })
  @ApiOkResponse({ description: 'Record updated successfully' })
  @ApiNotFoundResponse({ description: 'Record not found' })
  async update(
    @Param('id', ParseUUIDPipe) id: string,
    @Body() updateDto: UpdateDto,
  ): Promise<ApiResponse<T>> {
    const result = await this.service.update(id, updateDto);
    return createSuccessResponse(
      result,
      `${this.entityName} updated successfully`,
    );
  }

  @Delete(':id')
  @HttpCode(200)
  @ApiOperation({ summary: 'Delete a record (soft delete)' })
  @ApiOkResponse({ description: 'Record deleted successfully' })
  @ApiNotFoundResponse({ description: 'Record not found' })
  async delete(
    @Param('id', ParseUUIDPipe) id: string,
  ): Promise<ApiResponse<T>> {
    const result = await this.service.delete(id);
    return createSuccessResponse(
      result,
      `${this.entityName} deleted successfully`,
    );
  }

  @Post(':id/restore')
  @HttpCode(200)
  @ApiOperation({ summary: 'Restore a soft-deleted record' })
  @ApiOkResponse({ description: 'Record restored successfully' })
  async restore(
    @Param('id', ParseUUIDPipe) id: string,
  ): Promise<ApiResponse<T>> {
    const result = await this.service.restore(id);
    return createSuccessResponse(
      result,
      `${this.entityName} restored successfully`,
    );
  }
}
