import {
  Body,
  Controller,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  ParseUUIDPipe,
  Post,
  UseGuards,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { z } from 'zod';

import type { NodeListResponse, NodeSummary } from '@hexahost/contracts';

import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { SessionGuard } from '../auth/guards/session.guard';
import { ZodValidationPipe } from '../common/pipes/zod-validation.pipe';

import { AdminNodesService } from './admin-nodes.service';
import type { CreateNodeResponse } from './admin-nodes.service';

const createNodeRequestSchema = z.object({
  name: z.string().min(1).max(64),
  hostname: z.string().min(1).max(255),
  maxServers: z.number().int().min(1).max(1000).optional(),
  maxRamMb: z.number().int().min(2048).max(1048576).optional(),
  platformRamMb: z.number().int().min(512).max(65536).optional(),
});

const maintenanceRequestSchema = z.object({
  enabled: z.boolean(),
});

@ApiTags('admin')
@Controller('admin/nodes')
@UseGuards(SessionGuard)
export class AdminNodesController {
  constructor(private readonly adminNodesService: AdminNodesService) {}

  @Get()
  @ApiOperation({ summary: 'List game nodes (super admin only)' })
  list(@CurrentUser() user: { roles: string[] }): Promise<NodeListResponse> {
    this.adminNodesService.assertSuperAdmin(user.roles);
    return this.adminNodesService.listNodes();
  }

  @Post()
  @HttpCode(HttpStatus.CREATED)
  @ApiOperation({ summary: 'Register a new game node (super admin only)' })
  @ApiResponse({ status: 201, description: 'Node created with enrollment token' })
  create(
    @CurrentUser() user: { roles: string[] },
    @Body(new ZodValidationPipe(createNodeRequestSchema)) body: unknown,
  ): Promise<CreateNodeResponse> {
    this.adminNodesService.assertSuperAdmin(user.roles);

    return this.adminNodesService.createNode(
      body as Parameters<AdminNodesService['createNode']>[0],
    );
  }

  @Post(':id/drain')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Drain a game node (super admin only)' })
  drain(
    @CurrentUser() user: { roles: string[] },
    @Param('id', ParseUUIDPipe) id: string,
  ): Promise<NodeSummary> {
    this.adminNodesService.assertSuperAdmin(user.roles);
    return this.adminNodesService.requestDrain(id);
  }

  @Post(':id/maintenance')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Toggle maintenance mode for a node (super admin only)' })
  maintenance(
    @CurrentUser() user: { roles: string[] },
    @Param('id', ParseUUIDPipe) id: string,
    @Body(new ZodValidationPipe(maintenanceRequestSchema)) body: unknown,
  ): Promise<NodeSummary> {
    this.adminNodesService.assertSuperAdmin(user.roles);
    const input = body as z.infer<typeof maintenanceRequestSchema>;
    return this.adminNodesService.setMaintenance(id, input.enabled);
  }
}
