import { Body, Controller, Get, Param, Patch, Post, Query } from '@nestjs/common';
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
import { z } from 'zod';
import { CreateAsnSchema, UpdateAsnSchema, AsnListQuerySchema, ArriveAsnSchema, ReceiveLineSchema, ReverseReceiptSchema, CloseAsnSchema, ResolveDiscrepancySchema, CreateDockAppointmentSchema, UpdateDockAppointmentSchema, PaginationQuery } from '@wms/shared';
import { RequirePermissions, ApiKeyScopes } from '@/common/auth/decorators';
import { zodBody, zodQuery } from '@/common/validation/zod.pipe';
import { AsnService } from './asn.service';
import { ReceivingService } from './receiving.service';
import { DockService } from './dock.service';

const AsnQuery = AsnListQuerySchema.merge(PaginationQuery);
const CancelSchema = z.object({ reason: z.string().min(1).max(500) });

@ApiTags('inbound')
@ApiBearerAuth()
@Controller('inbound')
export class InboundController {
  constructor(
    private readonly asn: AsnService,
    private readonly receiving: ReceivingService,
    private readonly dock: DockService,
  ) {}

  @Get('asns') @RequirePermissions('inbound.read') @ApiKeyScopes('asn:read')
  list(@Query(zodQuery(AsnQuery)) q: z.infer<typeof AsnQuery>) { return this.asn.list(q); }

  @Get('asns/:id') @RequirePermissions('inbound.read') @ApiKeyScopes('asn:read')
  get(@Param('id') id: string) { return this.asn.get(id); }

  @Post('asns') @RequirePermissions('inbound.manage')
  create(@Body(zodBody(CreateAsnSchema)) dto: z.infer<typeof CreateAsnSchema>) { return this.asn.create(dto); }

  @Patch('asns/:id') @RequirePermissions('inbound.manage')
  update(@Param('id') id: string, @Body(zodBody(UpdateAsnSchema)) dto: z.infer<typeof UpdateAsnSchema>) { return this.asn.update(id, dto); }

  @Post('asns/:id/arrive') @RequirePermissions('inbound.receive')
  arrive(@Param('id') id: string, @Body(zodBody(ArriveAsnSchema)) dto: z.infer<typeof ArriveAsnSchema>) { return this.asn.arrive(id, dto); }

  @Post('asns/:id/cancel') @RequirePermissions('inbound.manage')
  cancel(@Param('id') id: string, @Body(zodBody(CancelSchema)) dto: z.infer<typeof CancelSchema>) { return this.asn.cancel(id, dto.reason); }

  @Post('asns/:id/receive') @RequirePermissions('inbound.receive')
  receive(@Param('id') id: string, @Body(zodBody(ReceiveLineSchema)) dto: z.infer<typeof ReceiveLineSchema>) { return this.receiving.receive(id, dto); }

  @Post('receipts/:id/reverse') @RequirePermissions('inbound.receive')
  reverse(@Param('id') id: string, @Body(zodBody(ReverseReceiptSchema)) dto: z.infer<typeof ReverseReceiptSchema>) { return this.receiving.reverseReceipt(id, dto.reason); }

  @Post('asns/:id/received') @RequirePermissions('inbound.receive')
  markReceived(@Param('id') id: string) { return this.receiving.markReceived(id); }

  @Post('asns/:id/close') @RequirePermissions('inbound.close')
  close(@Param('id') id: string, @Body(zodBody(CloseAsnSchema)) dto: z.infer<typeof CloseAsnSchema>) { return this.receiving.close(id, dto); }

  @Patch('discrepancies/:id') @RequirePermissions('inbound.close')
  resolveDiscrepancy(@Param('id') id: string, @Body(zodBody(ResolveDiscrepancySchema)) dto: z.infer<typeof ResolveDiscrepancySchema>) { return this.receiving.resolveDiscrepancy(id, dto); }

  @Get('dock-appointments') @RequirePermissions('inbound.read')
  listAppointments(@Query('warehouseId') warehouseId: string, @Query('from') from: string, @Query('to') to: string) { return this.dock.list(warehouseId, from, to); }

  @Post('dock-appointments') @RequirePermissions('inbound.manage')
  book(@Body(zodBody(CreateDockAppointmentSchema)) dto: z.infer<typeof CreateDockAppointmentSchema>) { return this.dock.create(dto); }

  @Patch('dock-appointments/:id') @RequirePermissions('inbound.manage')
  updateAppointment(@Param('id') id: string, @Body(zodBody(UpdateDockAppointmentSchema)) dto: z.infer<typeof UpdateDockAppointmentSchema>) { return this.dock.update(id, dto); }
}
