import { Body, Controller, Get, Param, Patch, Post, Query } from '@nestjs/common';
import { ApiBody, ApiNotFoundResponse, ApiOperation, ApiParam, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { UserRole } from '@prisma/client';
import { CurrentUser } from '../common/current-user.decorator';
import { RequireRole } from '../auth/require-role.decorator';
import { RequestUser } from '../common/request-user';
import { FeatureKey } from '../features/feature-catalog';
import { RequireFeature } from '../features/require-feature.decorator';
import {
  ApiNotFoundError,
  ApiProtectedEndpoint,
  ApiValidationError,
  ESTATE_ID_EXAMPLE,
  RESIDENT_ID_EXAMPLE,
  VISITOR_ID_EXAMPLE,
  VISITOR_PASS_ID_EXAMPLE
} from '../common/swagger-docs';
import { CreateVisitorDto } from './dto/create-visitor.dto';
import { CreateVisitorPassDto } from './dto/create-visitor-pass.dto';
import { UpdateVisitorRiskDto } from './dto/update-visitor-risk.dto';
import { VisitorsService } from './visitors.service';

@ApiTags('Visitors')
@ApiProtectedEndpoint()
@Controller({ path: 'visitors', version: '1' })
export class VisitorsController {
  constructor(private readonly visitorsService: VisitorsService) {}

  @Get()
  @RequireRole(UserRole.ESTATE_ADMIN, UserRole.SECURITY_SUPERVISOR, UserRole.GUARD, UserRole.RESIDENT)
  @RequireFeature(FeatureKey.VISITORS_VIEW)
  @ApiOperation({
    summary: 'List or search estate visitors',
    description: 'Returns visitor records scoped to the estate. Use q to search name, phone, or vehicle plate.'
  })
  @ApiQuery({ name: 'estateId', required: false, example: ESTATE_ID_EXAMPLE, description: 'Estate scope. Required for SUPER_ADMIN.' })
  @ApiQuery({ name: 'q', required: false, example: 'John', description: 'Optional visitor search text.' })
  @ApiResponse({
    status: 200,
    description: 'Visitors returned.',
    schema: {
      example: [
        {
          id: VISITOR_ID_EXAMPLE,
          estateId: ESTATE_ID_EXAMPLE,
          name: 'Ade Okafor',
          phone: '+2348111111111',
          vehiclePlate: 'LND-123-AB',
          photoUrl: null
        }
      ]
    }
  })
  findAll(@CurrentUser() user: RequestUser, @Query('estateId') estateId?: string, @Query('q') q?: string) {
    return this.visitorsService.findVisitors(user, estateId, q);
  }

  @Post()
  @RequireRole(UserRole.ESTATE_ADMIN, UserRole.RESIDENT)
  @RequireFeature(FeatureKey.VISITORS_CREATE)
  @ApiOperation({
    summary: 'Create visitor',
    description: 'Creates an estate-scoped visitor record that can later receive visitor passes.'
  })
  @ApiBody({ type: CreateVisitorDto })
  @ApiResponse({
    status: 201,
    description: 'Visitor created.',
    schema: {
      example: {
        id: VISITOR_ID_EXAMPLE,
        estateId: ESTATE_ID_EXAMPLE,
        name: 'Ade Okafor',
        phone: '+2348111111111',
        vehiclePlate: 'LND-123-AB',
        photoUrl: null
      }
    }
  })
  @ApiValidationError()
  createVisitor(@Body() dto: CreateVisitorDto, @CurrentUser() user: RequestUser) {
    return this.visitorsService.createVisitor(dto, user);
  }

  @Get('passes')
  @RequireRole(UserRole.ESTATE_ADMIN, UserRole.SECURITY_SUPERVISOR, UserRole.GUARD, UserRole.RESIDENT)
  @RequireFeature(FeatureKey.VISITOR_PASSES_VIEW)
  @ApiOperation({
    summary: 'List visitor passes',
    description: 'Returns recent visitor passes for an estate, including visitor and host resident context.'
  })
  @ApiQuery({ name: 'estateId', required: false, example: ESTATE_ID_EXAMPLE, description: 'Estate scope. Required for SUPER_ADMIN.' })
  @ApiResponse({
    status: 200,
    description: 'Visitor passes returned.',
    schema: {
      example: [
        {
          id: VISITOR_PASS_ID_EXAMPLE,
          estateId: ESTATE_ID_EXAMPLE,
          visitorId: VISITOR_ID_EXAMPLE,
          hostResidentId: RESIDENT_ID_EXAMPLE,
          visitorCode: 'ABC12345',
          status: 'ACTIVE',
          passType: 'SINGLE_USE',
          maxEntries: 1,
          entryCount: 0
        }
      ]
    }
  })
  findPasses(@CurrentUser() user: RequestUser, @Query('estateId') estateId?: string) {
    return this.visitorsService.findPasses(user, estateId);
  }

  @Post('passes')
  @RequireRole(UserRole.ESTATE_ADMIN, UserRole.RESIDENT)
  @RequireFeature(FeatureKey.VISITOR_PASSES_CREATE)
  @ApiOperation({
    summary: 'Create visitor pass',
    description:
      'Creates a visitor pass with a QR token and manual visitor code. The visitor and host resident must both belong to the estate.'
  })
  @ApiBody({ type: CreateVisitorPassDto })
  @ApiResponse({
    status: 201,
    description: 'Visitor pass created with QR payload.',
    schema: {
      example: {
        id: VISITOR_PASS_ID_EXAMPLE,
        estateId: ESTATE_ID_EXAMPLE,
        visitorId: VISITOR_ID_EXAMPLE,
        hostResidentId: RESIDENT_ID_EXAMPLE,
        visitorCode: 'ABC12345',
        qrToken: 'QRtokenExample123',
        qrPayload: { token: 'QRtokenExample123' },
        passType: 'SINGLE_USE',
        status: 'ACTIVE',
        maxEntries: 1,
        entryCount: 0
      }
    }
  })
  @ApiValidationError()
  @ApiNotFoundError('Host resident or visitor')
  createPass(@Body() dto: CreateVisitorPassDto, @CurrentUser() user: RequestUser) {
    return this.visitorsService.createPass(dto, user);
  }

  @Post('passes/:id/revoke')
  @RequireRole(UserRole.ESTATE_ADMIN, UserRole.SECURITY_SUPERVISOR)
  @RequireFeature(FeatureKey.VISITOR_PASSES_REVOKE)
  @ApiOperation({
    summary: 'Revoke visitor pass',
    description: 'Marks an existing visitor pass as REVOKED and records revokedAt.'
  })
  @ApiParam({ name: 'id', example: VISITOR_PASS_ID_EXAMPLE, description: 'Visitor pass ID to revoke.' })
  @ApiResponse({
    status: 201,
    description: 'Visitor pass revoked.',
    schema: {
      example: {
        id: VISITOR_PASS_ID_EXAMPLE,
        estateId: ESTATE_ID_EXAMPLE,
        status: 'REVOKED',
        revokedAt: '2026-05-16T12:00:00.000Z'
      }
    }
  })
  @ApiNotFoundResponse({
    description: 'Visitor pass was not found.',
    schema: { example: { statusCode: 404, message: 'Visitor pass not found', error: 'Not Found' } }
  })
  revokePass(@Param('id') id: string, @CurrentUser() user: RequestUser) {
    return this.visitorsService.revokePass(id, user);
  }

  @Get(':id/history')
  @RequireRole(UserRole.ESTATE_ADMIN, UserRole.SECURITY_SUPERVISOR, UserRole.GUARD, UserRole.RESIDENT)
  @RequireFeature(FeatureKey.VISITOR_INTELLIGENCE_VIEW)
  @ApiOperation({
    summary: 'View visitor intelligence history',
    description: 'Returns visit sessions, gates used, residents visited, exit reliability, and risk history for one visitor.'
  })
  @ApiParam({ name: 'id', example: VISITOR_ID_EXAMPLE })
  @ApiResponse({ status: 200, description: 'Visitor history returned.' })
  @ApiNotFoundError('Visitor')
  getHistory(@Param('id') id: string, @CurrentUser() user: RequestUser) {
    return this.visitorsService.getVisitorHistory(id, user);
  }

  @Patch(':id/risk')
  @RequireRole(UserRole.ESTATE_ADMIN, UserRole.SECURITY_SUPERVISOR)
  @RequireFeature(FeatureKey.VISITOR_INTELLIGENCE_MANAGE)
  @ApiOperation({
    summary: 'Update visitor risk',
    description: 'Flags, restricts, blacklists, scores, or annotates a visitor record for estate-internal risk tracking.'
  })
  @ApiParam({ name: 'id', example: VISITOR_ID_EXAMPLE })
  @ApiBody({ type: UpdateVisitorRiskDto })
  @ApiResponse({ status: 200, description: 'Visitor risk updated.' })
  @ApiNotFoundError('Visitor')
  @ApiValidationError()
  updateRisk(@Param('id') id: string, @Body() dto: UpdateVisitorRiskDto, @CurrentUser() user: RequestUser) {
    return this.visitorsService.updateRisk(id, dto, user);
  }
}
