import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  ParseUUIDPipe,
  Patch,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import type { PublicUser } from '../user/user.service';
import {
  DriveService,
  type DriveFileResponse,
  type DriveFolderResponse,
  type DriveListResponse,
  type PresignUploadResponse,
} from './drive.service';
import { CreateFolderDto } from './dto/create-folder.dto';
import { PresignUploadDto } from './dto/presign-upload.dto';
import { RenameDto } from './dto/rename.dto';

// 드라이브 컨트롤러 — 프로젝트와 독립된 개인 드라이브. 모든 엔드포인트 인증 필요.
@ApiTags('Drive')
@Controller('drive')
@UseGuards(JwtAuthGuard)
export class DriveController {
  constructor(private readonly driveService: DriveService) {}

  @Get()
  @ApiOperation({ summary: '드라이브 목록(폴더 미지정 시 루트)' })
  @ApiResponse({ status: 200, description: '목록 조회 성공' })
  @ApiResponse({ status: 403, description: '접근 권한 없음 (AUTH_003)' })
  list(
    @CurrentUser() user: PublicUser,
    @Query('folderId') folderId?: string,
  ): Promise<DriveListResponse> {
    return this.driveService.list(user.id, folderId);
  }

  /* ===================== 폴더 ===================== */

  @Post('folders')
  @HttpCode(HttpStatus.CREATED)
  @ApiOperation({ summary: '폴더 생성' })
  @ApiResponse({ status: 201, description: '생성 성공' })
  createFolder(
    @CurrentUser() user: PublicUser,
    @Body() dto: CreateFolderDto,
  ): Promise<DriveFolderResponse> {
    return this.driveService.createFolder(user.id, dto);
  }

  @Patch('folders/:folderId')
  @ApiOperation({ summary: '폴더 이름 변경' })
  @ApiResponse({ status: 200, description: '변경 성공' })
  renameFolder(
    @CurrentUser() user: PublicUser,
    @Param('folderId', ParseUUIDPipe) folderId: string,
    @Body() dto: RenameDto,
  ): Promise<DriveFolderResponse> {
    return this.driveService.renameFolder(user.id, folderId, dto.name);
  }

  @Delete('folders/:folderId')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '폴더 삭제(하위 폴더·파일 포함)' })
  @ApiResponse({ status: 200, description: '삭제 성공' })
  async deleteFolder(
    @CurrentUser() user: PublicUser,
    @Param('folderId', ParseUUIDPipe) folderId: string,
  ): Promise<null> {
    await this.driveService.deleteFolder(user.id, folderId);
    return null;
  }

  /* ===================== 파일 ===================== */

  @Post('files/presign')
  @HttpCode(HttpStatus.CREATED)
  @ApiOperation({ summary: '업로드용 presigned URL 발급(+pending 메타 생성)' })
  @ApiResponse({ status: 201, description: '발급 성공' })
  @ApiResponse({
    status: 400,
    description: '허용되지 않는 형식/크기 (VAL_001)',
  })
  presignUpload(
    @CurrentUser() user: PublicUser,
    @Body() dto: PresignUploadDto,
  ): Promise<PresignUploadResponse> {
    return this.driveService.presignUpload(user.id, dto);
  }

  @Post('files/:fileId/complete')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '업로드 확정(HEAD 검증 후 active 전환)' })
  @ApiResponse({ status: 200, description: '확정 성공' })
  @ApiResponse({ status: 400, description: '업로드 미완료/검증 실패' })
  completeUpload(
    @CurrentUser() user: PublicUser,
    @Param('fileId', ParseUUIDPipe) fileId: string,
  ): Promise<DriveFileResponse> {
    return this.driveService.completeUpload(user.id, fileId);
  }

  @Get('files/:fileId/download-url')
  @ApiOperation({ summary: '다운로드용 단기 presigned URL 발급' })
  @ApiResponse({ status: 200, description: '발급 성공' })
  @ApiResponse({ status: 404, description: '파일 없음/미확정 (RES_001)' })
  getDownloadUrl(
    @CurrentUser() user: PublicUser,
    @Param('fileId', ParseUUIDPipe) fileId: string,
  ): Promise<{ url: string }> {
    return this.driveService.getDownloadUrl(user.id, fileId);
  }

  @Patch('files/:fileId')
  @ApiOperation({ summary: '파일 이름 변경' })
  @ApiResponse({ status: 200, description: '변경 성공' })
  renameFile(
    @CurrentUser() user: PublicUser,
    @Param('fileId', ParseUUIDPipe) fileId: string,
    @Body() dto: RenameDto,
  ): Promise<DriveFileResponse> {
    return this.driveService.renameFile(user.id, fileId, dto.name);
  }

  @Delete('files/:fileId')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '파일 삭제' })
  @ApiResponse({ status: 200, description: '삭제 성공' })
  async deleteFile(
    @CurrentUser() user: PublicUser,
    @Param('fileId', ParseUUIDPipe) fileId: string,
  ): Promise<null> {
    await this.driveService.deleteFile(user.id, fileId);
    return null;
  }
}
