import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Query,
  Req,
  UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { UserRole } from '@prisma/client';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { RolesGuard } from '../../common/guards/roles.guard';
import { Roles } from '../../common/decorators/roles.decorator';
import { Permissions } from '../../common/decorators/permissions.decorator';
import { PermissionsGuard } from '../../common/guards/permissions.guard';
import { CreateCouponDto } from './dto/create-coupon.dto';
import { UpdateCouponDto } from './dto/update-coupon.dto';
import { CouponsService } from './coupons.service';
import { BulkCreateCouponDto } from './dto/bulk-create-coupon.dto';
import { RejectCouponDto } from './dto/reject-coupon.dto';
import { PublishCouponDto } from './dto/publish-coupon.dto';

type RequestWithUser = {
  user: { id: string; role: UserRole; shopId: string | null };
};

@ApiTags('coupons')
@ApiBearerAuth()
@Controller('coupons')
@UseGuards(JwtAuthGuard, RolesGuard, PermissionsGuard)
@Roles(UserRole.SUPERADMIN, UserRole.ADMIN, UserRole.SUBADMIN)
@Permissions('coupons')
export class CouponsController {
  constructor(private readonly coupons: CouponsService) {}

  @Get()
  @ApiOkResponse({
    description: 'List coupons for current shop (or shopId for SUPERADMIN)',
  })
  list(@Req() req: RequestWithUser, @Query('shopId') shopId?: string) {
    return this.coupons.list(req.user, shopId);
  }

  @Get('paged')
  @ApiOkResponse({
    description: 'Paginated list of coupons (current shop; optional filters)',
  })
  listPaged(
    @Req() req: RequestWithUser,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('q') q?: string,
    @Query('status') status?: string,
    @Query('moderationStatus') moderationStatus?: string,
    @Query('shopId') shopId?: string,
  ) {
    const p = page != null ? Number(page) : null;
    const l = limit != null ? Number(limit) : null;
    const wantsPaged =
      (p != null && Number.isFinite(p)) || (l != null && Number.isFinite(l));
    const pageNum =
      p != null && Number.isFinite(p) ? Math.max(1, Math.floor(p)) : 1;
    const limitNum =
      l != null && Number.isFinite(l)
        ? Math.min(100, Math.max(1, Math.floor(l)))
        : 20;

    return this.coupons.listPaged(req.user, {
      page: wantsPaged ? pageNum : 1,
      limit: wantsPaged ? limitNum : 20,
      q: (q ?? '').toString(),
      status: status?.toString(),
      moderationStatus: moderationStatus?.toString(),
      shopId: shopId?.toString(),
    });
  }

  @Get('admin')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.SUPERADMIN)
  @ApiBearerAuth('bearer')
  @ApiOkResponse({
    description: 'Admin list of coupons (paginated + searchable)',
  })
  listAdmin(
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('q') q?: string,
    @Query('shopId') shopId?: string,
    @Query('status') status?: string,
    @Query('moderationStatus') moderationStatus?: string,
  ) {
    const p = page != null ? Number(page) : null;
    const l = limit != null ? Number(limit) : null;
    const wantsPaged =
      (p != null && Number.isFinite(p)) || (l != null && Number.isFinite(l));
    const pageNum =
      p != null && Number.isFinite(p) ? Math.max(1, Math.floor(p)) : 1;
    const limitNum =
      l != null && Number.isFinite(l)
        ? Math.min(100, Math.max(1, Math.floor(l)))
        : 20;

    return this.coupons.listAdminPaged({
      page: wantsPaged ? pageNum : 1,
      limit: wantsPaged ? limitNum : 50,
      q: (q ?? '').toString(),
      shopId: shopId?.toString(),
      status: status?.toString(),
      moderationStatus: moderationStatus?.toString(),
    });
  }

  @Post()
  @ApiOkResponse({ description: 'Create coupon' })
  create(@Req() req: RequestWithUser, @Body() dto: CreateCouponDto) {
    return this.coupons.create(req.user, dto);
  }

  @Post('bulk')
  @ApiOkResponse({ description: 'Create same coupon for multiple shops' })
  bulkCreate(@Req() req: RequestWithUser, @Body() dto: BulkCreateCouponDto) {
    return this.coupons.bulkCreate(req.user, dto);
  }

  @Patch(':id')
  @ApiOkResponse({ description: 'Update coupon' })
  update(
    @Req() req: RequestWithUser,
    @Param('id') id: string,
    @Body() dto: UpdateCouponDto,
  ) {
    return this.coupons.update(req.user, id, dto);
  }

  @Post(':id/submit')
  @ApiOkResponse({ description: 'Submit coupon for review' })
  submit(@Req() req: RequestWithUser, @Param('id') id: string) {
    return this.coupons.submit(req.user, id);
  }

  @Get(':id/customers')
  @ApiOkResponse({ description: 'List customers issued/redeemed for a coupon' })
  listCouponCustomers(@Req() req: RequestWithUser, @Param('id') id: string) {
    return this.coupons.listCouponCustomers(req.user, id);
  }

  @Post(':id/publish')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.SUPERADMIN)
  @ApiBearerAuth('bearer')
  @ApiOkResponse({ description: 'Publish coupon (approve)' })
  publish(@Param('id') id: string, @Body() dto: PublishCouponDto) {
    return this.coupons.publish(id, dto);
  }

  @Post(':id/reject')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.SUPERADMIN)
  @ApiBearerAuth('bearer')
  @ApiOkResponse({ description: 'Reject coupon with reason' })
  reject(@Param('id') id: string, @Body() dto: RejectCouponDto) {
    return this.coupons.reject(id, dto);
  }

  @Delete(':id')
  @ApiOkResponse({ description: 'Delete coupon' })
  remove(@Req() req: RequestWithUser, @Param('id') id: string) {
    return this.coupons.remove(req.user, id);
  }
}
