/**
 * StorageController - Endpoints para gestión de archivos
 *
 * @swagger
 * tags:
 *   name: Storage
 *   description: Gestión de almacenamiento de archivos
 *
 * @module Storage
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { StorageService } from '../services/storage.service';
import { AuthMiddleware } from '../../auth/middleware/auth.middleware';
import { AuthService } from '../../auth/services/auth.service';
import { User } from '../../core/entities/user.entity';
import { Tenant } from '../../core/entities/tenant.entity';
import { RefreshToken } from '../../auth/entities/refresh-token.entity';

interface ServiceContext {
  tenantId: string;
  userId?: string;
}

/**
 * Create the storage controller with routes
 *
 * @swagger
 * /api/storage/files:
 *   get:
 *     tags: [Storage]
 *     summary: List files
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: bucketId
 *         schema:
 *           type: string
 *       - in: query
 *         name: folderId
 *         schema:
 *           type: string
 *       - in: query
 *         name: search
 *         schema:
 *           type: string
 *     responses:
 *       200:
 *         description: List of files
 */
export function createStorageController(dataSource: DataSource): Router {
  const router = Router();

  // Repositories
  const userRepository = dataSource.getRepository(User);
  const tenantRepository = dataSource.getRepository(Tenant);
  const refreshTokenRepository = dataSource.getRepository(RefreshToken);

  // Services
  const storageService = new StorageService(dataSource);
  const authService = new AuthService(userRepository, tenantRepository, refreshTokenRepository as any);
  const authMiddleware = new AuthMiddleware(authService, dataSource);

  // Helper to create service context
  const getContext = (req: Request): ServiceContext => {
    if (!req.tenantId) {
      throw new Error('Tenant ID is required');
    }
    return {
      tenantId: req.tenantId,
      userId: req.user?.sub,
    };
  };

  /**
   * @swagger
   * /api/storage/files:
   *   get:
   *     tags: [Storage]
   *     summary: List files with filters
   */
  router.get(
    '/files',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const filters = {
          bucketId: req.query.bucketId as string,
          folderId: req.query.folderId as string,
          mimeType: req.query.mimeType as string,
          search: req.query.search as string,
          status: req.query.status as string,
          entityType: req.query.entityType as string,
          entityId: req.query.entityId as string,
          createdFrom: req.query.createdFrom
            ? new Date(req.query.createdFrom as string)
            : undefined,
          createdTo: req.query.createdTo
            ? new Date(req.query.createdTo as string)
            : undefined,
          page: parseInt(req.query.page as string) || 1,
          limit: parseInt(req.query.limit as string) || 20,
        };

        const result = await storageService.findAll(ctx, filters);
        res.json(result);
      } catch (error) {
        next(error);
      }
    }
  );

  /**
   * @swagger
   * /api/storage/files/{id}:
   *   get:
   *     tags: [Storage]
   *     summary: Get file by ID
   */
  router.get(
    '/files/:id',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const file = await storageService.findById(ctx, req.params.id);

        if (!file) {
          res.status(404).json({ error: 'File not found' });
          return;
        }

        res.json(file);
      } catch (error) {
        next(error);
      }
    }
  );

  /**
   * @swagger
   * /api/storage/upload/request:
   *   post:
   *     tags: [Storage]
   *     summary: Request upload URL
   */
  router.post(
    '/upload/request',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const { bucketId, fileName, mimeType, sizeBytes } = req.body;

        if (!bucketId || !fileName || !mimeType || !sizeBytes) {
          res.status(400).json({
            error: 'Bad Request',
            message: 'bucketId, fileName, mimeType, and sizeBytes are required',
          });
          return;
        }

        const result = await storageService.generateUploadUrl(
          ctx,
          bucketId,
          fileName,
          mimeType,
          sizeBytes
        );

        res.json(result);
      } catch (error) {
        next(error);
      }
    }
  );

  /**
   * @swagger
   * /api/storage/upload/{uploadId}/complete:
   *   post:
   *     tags: [Storage]
   *     summary: Complete upload
   */
  router.post(
    '/upload/:uploadId/complete',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const { storageKey, actualSize, checksum } = req.body;

        const file = await storageService.completeUpload(
          ctx,
          req.params.uploadId,
          storageKey,
          actualSize,
          checksum
        );

        res.status(201).json(file);
      } catch (error) {
        next(error);
      }
    }
  );

  /**
   * @swagger
   * /api/storage/files/{id}/download-url:
   *   get:
   *     tags: [Storage]
   *     summary: Get download URL for file
   */
  router.get(
    '/files/:id/download-url',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const expiresInMinutes = parseInt(req.query.expires as string) || 60;

        const downloadUrl = await storageService.generateDownloadUrl(
          ctx,
          req.params.id,
          expiresInMinutes
        );

        res.json({ downloadUrl, expiresInMinutes });
      } catch (error) {
        next(error);
      }
    }
  );

  /**
   * @swagger
   * /api/storage/files/{id}:
   *   delete:
   *     tags: [Storage]
   *     summary: Delete file
   */
  router.delete(
    '/files/:id',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const deleted = await storageService.deleteFile(ctx, req.params.id);

        if (!deleted) {
          res.status(404).json({ error: 'File not found' });
          return;
        }

        res.status(204).send();
      } catch (error) {
        next(error);
      }
    }
  );

  /**
   * @swagger
   * /api/storage/files/{id}/copy:
   *   post:
   *     tags: [Storage]
   *     summary: Copy file
   */
  router.post(
    '/files/:id/copy',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const { targetFolderId } = req.body;

        const copiedFile = await storageService.copyFile(
          ctx,
          req.params.id,
          targetFolderId
        );

        res.status(201).json(copiedFile);
      } catch (error) {
        next(error);
      }
    }
  );

  /**
   * @swagger
   * /api/storage/usage:
   *   get:
   *     tags: [Storage]
   *     summary: Get tenant storage usage
   */
  router.get(
    '/usage',
    authMiddleware.authenticate,
    async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      try {
        const ctx = getContext(req);
        const bucketId = req.query.bucketId as string;
        const usage = await storageService.getTenantUsage(ctx, bucketId);
        res.json(usage);
      } catch (error) {
        next(error);
      }
    }
  );

  return router;
}
