import {
  Controller,
  Post,
  Get,
  Delete,
  Body,
  UseGuards,
  HttpCode,
  HttpStatus,
  Logger,
  Param,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiParam } from '@nestjs/swagger';
import { InvitationService } from '../services/invitation.service';
import { CreateInvitationDto, InvitationResponseDto } from '../dto/invitation.dto';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { RolesGuard } from '../guards/roles.guard';
import { Roles } from '../decorators/roles.decorator';
import { CurrentUser, UserPayload } from '../decorators/current-user.decorator';
import { Public } from '../decorators/public.decorator';
import { UserRole } from '@domain/entities/user.entity';

/**
 * Invitations Controller
 *
 * Handles user invitation endpoints:
 * - POST /invitations - Create invitation (admin/manager)
 * - GET /invitations/verify/:token - Verify invitation (public)
 * - GET /invitations - List organization invitations (admin/manager)
 */
@ApiTags('Invitations')
@Controller('invitations')
export class InvitationsController {
  private readonly logger = new Logger(InvitationsController.name);

  constructor(private readonly invitationService: InvitationService) {}

  /**
   * Create invitation and send email
   */
  @Post()
  @HttpCode(HttpStatus.CREATED)
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('admin', 'manager')
  @ApiBearerAuth()
  @ApiOperation({
    summary: 'Create invitation',
    description: 'Send an invitation email to a new user. Admin/manager only.',
  })
  @ApiResponse({
    status: 201,
    description: 'Invitation created successfully',
    type: InvitationResponseDto,
  })
  @ApiResponse({
    status: 403,
    description: 'Forbidden - requires admin or manager role',
  })
  @ApiResponse({
    status: 409,
    description: 'Conflict - user or active invitation already exists',
  })
  async createInvitation(
    @Body() dto: CreateInvitationDto,
    @CurrentUser() user: UserPayload
  ): Promise<InvitationResponseDto> {
    this.logger.log(`[User: ${user.email}] Creating invitation for: ${dto.email}`);

    const invitation = await this.invitationService.createInvitation(
      dto.email,
      dto.firstName,
      dto.lastName,
      dto.role as unknown as UserRole,
      user.organizationId,
      user.id,
      user.role
    );

    return {
      id: invitation.id,
      token: invitation.token,
      email: invitation.email,
      firstName: invitation.firstName,
      lastName: invitation.lastName,
      role: invitation.role,
      organizationId: invitation.organizationId,
      expiresAt: invitation.expiresAt,
      isUsed: invitation.isUsed,
      usedAt: invitation.usedAt,
      createdAt: invitation.createdAt,
    };
  }

  /**
   * Verify invitation token
   */
  @Get('verify/:token')
  @Public()
  @ApiOperation({
    summary: 'Verify invitation token',
    description: 'Check if an invitation token is valid and not expired. Public endpoint.',
  })
  @ApiParam({
    name: 'token',
    description: 'Invitation token',
    example: 'abc123def456',
  })
  @ApiResponse({
    status: 200,
    description: 'Invitation is valid',
    type: InvitationResponseDto,
  })
  @ApiResponse({
    status: 404,
    description: 'Invitation not found',
  })
  @ApiResponse({
    status: 400,
    description: 'Invitation expired or already used',
  })
  async verifyInvitation(@Param('token') token: string): Promise<InvitationResponseDto> {
    this.logger.log(`Verifying invitation token: ${token}`);

    const invitation = await this.invitationService.verifyInvitation(token);

    return {
      id: invitation.id,
      token: invitation.token,
      email: invitation.email,
      firstName: invitation.firstName,
      lastName: invitation.lastName,
      role: invitation.role,
      organizationId: invitation.organizationId,
      expiresAt: invitation.expiresAt,
      isUsed: invitation.isUsed,
      usedAt: invitation.usedAt,
      createdAt: invitation.createdAt,
    };
  }

  /**
   * Cancel (delete) a pending invitation
   */
  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('admin', 'manager')
  @ApiBearerAuth()
  @ApiOperation({
    summary: 'Cancel invitation',
    description: 'Delete a pending invitation. Admin/manager only.',
  })
  @ApiResponse({ status: 204, description: 'Invitation cancelled' })
  @ApiResponse({ status: 404, description: 'Invitation not found' })
  @ApiResponse({ status: 400, description: 'Invitation already used' })
  async cancelInvitation(@Param('id') id: string, @CurrentUser() user: UserPayload): Promise<void> {
    this.logger.log(`[User: ${user.email}] Cancelling invitation: ${id}`);
    await this.invitationService.cancelInvitation(id, user.organizationId);
  }

  /**
   * List organization invitations
   */
  @Get()
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('admin', 'manager')
  @ApiBearerAuth()
  @ApiOperation({
    summary: 'List invitations',
    description: 'Get all invitations for the current organization. Admin/manager only.',
  })
  @ApiResponse({
    status: 200,
    description: 'Invitations retrieved successfully',
    type: [InvitationResponseDto],
  })
  @ApiResponse({
    status: 403,
    description: 'Forbidden - requires admin or manager role',
  })
  async listInvitations(@CurrentUser() user: UserPayload): Promise<InvitationResponseDto[]> {
    this.logger.log(`[User: ${user.email}] Listing invitations for organization`);

    const invitations = await this.invitationService.getOrganizationInvitations(
      user.organizationId
    );

    return invitations.map(invitation => ({
      id: invitation.id,
      token: invitation.token,
      email: invitation.email,
      firstName: invitation.firstName,
      lastName: invitation.lastName,
      role: invitation.role,
      organizationId: invitation.organizationId,
      expiresAt: invitation.expiresAt,
      isUsed: invitation.isUsed,
      usedAt: invitation.usedAt,
      createdAt: invitation.createdAt,
    }));
  }
}
