import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  Res,
  UploadedFile,
  UseInterceptors,
  ParseIntPipe,
  HttpCode,
  HttpStatus,
  StreamableFile,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { Response } from 'express';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
  ApiParam,
  ApiQuery,
  ApiConsumes,
  ApiBody,
} from '@nestjs/swagger';
import { EcoDmsService } from './ecodms.service';
import {
  SearchDocumentsDto,
  UploadDocumentDto,
  UpdateDocumentDto,
  ListDocumentsDto,
  CreateFolderDto,
  DocumentResponseDto,
  FolderResponseDto,
  ClassificationResponseDto,
  SearchResultResponseDto,
  SortOrder,
} from './ecodms.types';
import { RequirePermissions } from '../../../../auth/permissions/permissions.decorator';
import { Permission } from '../../../../auth/permissions/permissions.enum';

/**
 * ecoDMS Integration Controller
 *
 * REST API endpoints for ecoDMS document management integration.
 */
@ApiTags('Integrations - ecoDMS')
@ApiBearerAuth()
@Controller('integrations/ecodms')
export class EcoDmsController {
  constructor(private readonly ecoDmsService: EcoDmsService) {}

  // ============ Health & Status ============

  @Post('test')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Test ecoDMS connection' })
  @ApiResponse({
    status: 200,
    description: 'Connection test result',
    schema: {
      type: 'object',
      properties: {
        success: { type: 'boolean' },
        message: { type: 'string' },
        latency: { type: 'number' },
      },
    },
  })
  @RequirePermissions(Permission.INTEGRATIONS_MANAGE)
  async testConnection() {
    return this.ecoDmsService.testConnection();
  }

  @Get('health')
  @ApiOperation({ summary: 'Get ecoDMS connector health status' })
  @ApiResponse({
    status: 200,
    description: 'Health status',
    schema: {
      type: 'object',
      properties: {
        status: { type: 'string', enum: ['connected', 'error', 'not_configured'] },
        lastCheck: { type: 'string', format: 'date-time' },
        latency: { type: 'number' },
        error: { type: 'string' },
      },
    },
  })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async getHealth() {
    return this.ecoDmsService.checkHealth();
  }

  // ============ Documents ============

  @Get('documents')
  @ApiOperation({ summary: 'List documents' })
  @ApiQuery({ name: 'folderId', required: false, type: Number })
  @ApiQuery({ name: 'classifyId', required: false, type: Number })
  @ApiQuery({ name: 'recursive', required: false, type: Boolean })
  @ApiQuery({ name: 'sortBy', required: false, type: String })
  @ApiQuery({ name: 'sortOrder', required: false, enum: SortOrder })
  @ApiQuery({ name: 'page', required: false, type: Number })
  @ApiQuery({ name: 'pageSize', required: false, type: Number })
  @ApiResponse({
    status: 200,
    description: 'List of documents',
    schema: {
      type: 'object',
      properties: {
        documents: { type: 'array', items: { $ref: '#/components/schemas/DocumentResponseDto' } },
        pagination: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            total: { type: 'number' },
            totalPages: { type: 'number' },
          },
        },
      },
    },
  })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async listDocuments(@Query() query: ListDocumentsDto) {
    return this.ecoDmsService.listDocuments(query);
  }

  @Get('documents/:id')
  @ApiOperation({ summary: 'Get a document by ID' })
  @ApiParam({ name: 'id', type: Number })
  @ApiResponse({ status: 200, description: 'Document details', type: DocumentResponseDto })
  @ApiResponse({ status: 404, description: 'Document not found' })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async getDocument(@Param('id', ParseIntPipe) id: number) {
    return this.ecoDmsService.getDocument(id);
  }

  @Post('documents/search')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Search documents' })
  @ApiResponse({ status: 200, description: 'Search results', type: SearchResultResponseDto })
  @RequirePermissions(Permission.INTEGRATIONS_MANAGE)
  async searchDocuments(@Body() params: SearchDocumentsDto) {
    return this.ecoDmsService.searchDocuments(params);
  }

  @Post('documents/upload')
  @UseInterceptors(FileInterceptor('file'))
  @ApiOperation({ summary: 'Upload a document' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        file: { type: 'string', format: 'binary' },
        title: { type: 'string' },
        classifyId: { type: 'number' },
        folderId: { type: 'number' },
        fileName: { type: 'string' },
        documentDate: { type: 'string', format: 'date' },
        enableOcr: { type: 'boolean' },
        attributes: { type: 'object' },
      },
      required: ['file', 'title', 'classifyId'],
    },
  })
  @ApiResponse({ status: 201, description: 'Document uploaded', type: DocumentResponseDto })
  @RequirePermissions(Permission.INTEGRATIONS_MANAGE)
  async uploadDocument(
    @UploadedFile() file: Express.Multer.File,
    @Body() metadata: UploadDocumentDto,
  ) {
    return this.ecoDmsService.uploadDocument(
      file.buffer,
      file.originalname,
      file.mimetype,
      metadata,
    );
  }

  @Put('documents/:id')
  @ApiOperation({ summary: 'Update document metadata' })
  @ApiParam({ name: 'id', type: Number })
  @ApiResponse({ status: 200, description: 'Document updated', type: DocumentResponseDto })
  @ApiResponse({ status: 404, description: 'Document not found' })
  @RequirePermissions(Permission.INTEGRATIONS_MANAGE)
  async updateDocument(
    @Param('id', ParseIntPipe) id: number,
    @Body() data: UpdateDocumentDto,
  ) {
    return this.ecoDmsService.updateDocument(id, data);
  }

  @Delete('documents/:id')
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Delete a document' })
  @ApiParam({ name: 'id', type: Number })
  @ApiResponse({ status: 204, description: 'Document deleted' })
  @ApiResponse({ status: 404, description: 'Document not found' })
  @RequirePermissions(Permission.INTEGRATIONS_MANAGE)
  async deleteDocument(@Param('id', ParseIntPipe) id: number): Promise<void> {
    await this.ecoDmsService.deleteDocument(id);
  }

  @Get('documents/:id/download')
  @ApiOperation({ summary: 'Download document content' })
  @ApiParam({ name: 'id', type: Number })
  @ApiResponse({ status: 200, description: 'Document content' })
  @ApiResponse({ status: 404, description: 'Document not found' })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async downloadDocument(
    @Param('id', ParseIntPipe) id: number,
    @Res({ passthrough: true }) res: Response,
  ): Promise<StreamableFile> {
    const { content, fileName, mimeType } = await this.ecoDmsService.downloadDocument(id);

    res.set({
      'Content-Type': mimeType,
      'Content-Disposition': `attachment; filename="${fileName}"`,
      'Content-Length': content.length,
    });

    return new StreamableFile(content);
  }

  @Get('documents/:id/preview')
  @ApiOperation({ summary: 'Get document preview (thumbnail)' })
  @ApiParam({ name: 'id', type: Number })
  @ApiQuery({ name: 'page', required: false, type: Number, description: 'Page number for multi-page documents' })
  @ApiResponse({ status: 200, description: 'Preview image' })
  @ApiResponse({ status: 404, description: 'Document not found' })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async getDocumentPreview(
    @Param('id', ParseIntPipe) id: number,
    @Query('page') page?: number,
    @Res({ passthrough: true }) res?: Response,
  ): Promise<StreamableFile> {
    const preview = await this.ecoDmsService.getDocumentPreview(id, page || 1);

    res?.set({
      'Content-Type': 'image/png',
      'Content-Length': preview.length,
      'Cache-Control': 'public, max-age=3600',
    });

    return new StreamableFile(preview);
  }

  // ============ Folders ============

  @Get('folders')
  @ApiOperation({ summary: 'List folders' })
  @ApiQuery({ name: 'parentId', required: false, type: Number, description: 'Parent folder ID (null for root)' })
  @ApiResponse({ status: 200, description: 'List of folders', type: [FolderResponseDto] })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async listFolders(@Query('parentId') parentId?: number) {
    return this.ecoDmsService.listFolders(parentId);
  }

  @Get('folders/tree')
  @ApiOperation({ summary: 'Get complete folder tree' })
  @ApiResponse({ status: 200, description: 'Folder tree', type: [FolderResponseDto] })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async getFolderTree() {
    return this.ecoDmsService.getFolderTree();
  }

  @Post('folders')
  @HttpCode(HttpStatus.CREATED)
  @ApiOperation({ summary: 'Create a folder' })
  @ApiResponse({ status: 201, description: 'Folder created', type: FolderResponseDto })
  @RequirePermissions(Permission.INTEGRATIONS_MANAGE)
  async createFolder(@Body() data: CreateFolderDto) {
    return this.ecoDmsService.createFolder(data);
  }

  @Delete('folders/:id')
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Delete a folder' })
  @ApiParam({ name: 'id', type: Number })
  @ApiResponse({ status: 204, description: 'Folder deleted' })
  @ApiResponse({ status: 404, description: 'Folder not found' })
  @RequirePermissions(Permission.INTEGRATIONS_MANAGE)
  async deleteFolder(@Param('id', ParseIntPipe) id: number): Promise<void> {
    await this.ecoDmsService.deleteFolder(id);
  }

  // ============ Classifications ============

  @Get('classifications')
  @ApiOperation({ summary: 'List all classifications (document types)' })
  @ApiResponse({ status: 200, description: 'List of classifications', type: [ClassificationResponseDto] })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async listClassifications() {
    return this.ecoDmsService.listClassifications();
  }

  @Get('classifications/:id')
  @ApiOperation({ summary: 'Get classification details' })
  @ApiParam({ name: 'id', type: Number })
  @ApiResponse({ status: 200, description: 'Classification details', type: ClassificationResponseDto })
  @ApiResponse({ status: 404, description: 'Classification not found' })
  @RequirePermissions(Permission.INTEGRATIONS_VIEW)
  async getClassification(@Param('id', ParseIntPipe) id: number) {
    return this.ecoDmsService.getClassification(id);
  }
}
