import { Controller, Post, Get, Put, Body, Param, Query } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { CurrentTenant } from '../../common/decorators/current-tenant.decorator';
import { RequirePermission } from '../../common/decorators/require-permission.decorator';
import { InstancesService, LifecycleFunc } from './instances.service';

@ApiTags('instances')
@ApiBearerAuth()
@Controller('instances')
export class InstancesController {
  constructor(private readonly instances: InstancesService) {}

  @Post(':id/lifecycle')
  @RequirePermission('server.manage')
  @ApiOperation({ summary: 'Send a lifecycle command to a game instance (start/stop/restart/status/steam_update)' })
  async lifecycle(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { action: LifecycleFunc },
  ) {
    return this.instances.lifecycle(licenseId, id, body.action);
  }

  @Post(':id/rcon')
  @RequirePermission('server.console')
  @ApiOperation({ summary: 'Send an RCON/console command to a game instance' })
  async rcon(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { command: string },
  ) {
    return this.instances.rcon(licenseId, id, body.command);
  }

  @Get(':id/files')
  @RequirePermission('files.view')
  @ApiOperation({ summary: 'List a directory in the instance (jailed to its root)' })
  async listFiles(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Query('path') path?: string,
  ) {
    return this.instances.listFiles(licenseId, id, path ?? '');
  }

  @Get(':id/file')
  @RequirePermission('files.view')
  @ApiOperation({ summary: 'Read a text file from the instance (jailed, 5 MiB cap)' })
  async readFile(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Query('path') path: string,
  ) {
    return this.instances.readFile(licenseId, id, path);
  }

  @Put(':id/file')
  @RequirePermission('files.manage')
  @ApiOperation({ summary: 'Write a text file in the instance (jailed)' })
  async writeFile(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { path: string; content: string },
  ) {
    return this.instances.writeFile(licenseId, id, body.path, body.content ?? '');
  }

  @Post(':id/files/delete')
  @RequirePermission('files.manage')
  @ApiOperation({ summary: 'Delete a file or directory (jailed)' })
  async deleteFile(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { path: string },
  ) {
    return this.instances.deleteFile(licenseId, id, body.path);
  }

  @Post(':id/files/rename')
  @RequirePermission('files.manage')
  @ApiOperation({ summary: 'Rename a file/directory within its parent (jailed)' })
  async renameFile(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { path: string; name: string },
  ) {
    return this.instances.renameFile(licenseId, id, body.path, body.name);
  }

  @Post(':id/files/mkdir')
  @RequirePermission('files.manage')
  @ApiOperation({ summary: 'Create a directory (jailed)' })
  async mkdir(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { path: string },
  ) {
    return this.instances.mkdir(licenseId, id, body.path);
  }

  @Post(':id/files/mkfile')
  @RequirePermission('files.manage')
  @ApiOperation({ summary: 'Create an empty file (jailed)' })
  async mkfile(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { path: string },
  ) {
    return this.instances.mkfile(licenseId, id, body.path);
  }

  @Post(':id/files/move')
  @RequirePermission('files.manage')
  @ApiOperation({ summary: 'Move a file/directory (jailed)' })
  async moveFile(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { path: string; dest: string },
  ) {
    return this.instances.moveFile(licenseId, id, body.path, body.dest);
  }

  @Post(':id/files/copy')
  @RequirePermission('files.manage')
  @ApiOperation({ summary: 'Copy a file/directory (jailed)' })
  async copyFile(
    @CurrentTenant() licenseId: string,
    @Param('id') id: string,
    @Body() body: { path: string; dest: string },
  ) {
    return this.instances.copyFile(licenseId, id, body.path, body.dest);
  }
}
