/**
 * PreferencesController - Controller de Preferencias de Usuario
 *
 * Endpoints REST para gestión de preferencias personalizadas.
 *
 * @module Profiles
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { PreferencesService } from '../services/preferences.service';
import { AvatarService } from '../services/avatar.service';
import { ProfileCompletionService } from '../services/profile-completion.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;
}

export function createPreferencesController(dataSource: DataSource): Router {
  const router = Router();

  // Services
  const preferencesService = new PreferencesService(dataSource);
  const avatarService = new AvatarService(dataSource);
  const completionService = new ProfileCompletionService(dataSource);
  const userRepository = dataSource.getRepository(User);
  const tenantRepository = dataSource.getRepository(Tenant);
  const refreshTokenRepository = dataSource.getRepository(RefreshToken);
  const authService = new AuthService(userRepository, tenantRepository, refreshTokenRepository as any);
  const authMiddleware = new AuthMiddleware(authService, dataSource);

  // Helper to get 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,
    };
  };

  // ============ User Preferences ============

  /**
   * GET /me/preferences
   * Get current user's preferences
   */
  router.get('/me/preferences', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.getPreferences(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /me/preferences
   * Update current user's preferences
   */
  router.put('/me/preferences', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.updatePreferences(getContext(req), req.user.sub, req.body);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /me/preferences/reset
   * Reset preferences to defaults
   */
  router.post('/me/preferences/reset', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.resetPreferences(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: preferences, message: 'Preferences reset to defaults' });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/preferences/ui
   * Get UI preferences
   */
  router.get('/me/preferences/ui', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.getUIPreferences(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /me/preferences/ui
   * Update UI preferences
   */
  router.put('/me/preferences/ui', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.updateUIPreferences(getContext(req), req.user.sub, req.body);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/preferences/notifications
   * Get notification preferences
   */
  router.get('/me/preferences/notifications', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.getNotificationPreferences(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /me/preferences/notifications
   * Update notification preferences
   */
  router.put('/me/preferences/notifications', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.updateNotificationPreferences(getContext(req), req.user.sub, req.body);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/preferences/privacy
   * Get privacy preferences
   */
  router.get('/me/preferences/privacy', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.getPrivacyPreferences(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /me/preferences/privacy
   * Update privacy preferences
   */
  router.put('/me/preferences/privacy', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.updatePrivacyPreferences(getContext(req), req.user.sub, req.body);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/preferences/accessibility
   * Get accessibility preferences
   */
  router.get('/me/preferences/accessibility', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.getAccessibilityPreferences(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /me/preferences/accessibility
   * Update accessibility preferences
   */
  router.put('/me/preferences/accessibility', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const preferences = await preferencesService.updateAccessibilityPreferences(getContext(req), req.user.sub, req.body);
      res.status(200).json({ success: true, data: preferences });
    } catch (error) {
      next(error);
    }
  });

  // ============ Avatar Management ============

  /**
   * POST /me/avatar/upload-url
   * Generate presigned upload URL for avatar
   */
  router.post('/me/avatar/upload-url', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const { mimeType } = req.body;
      if (!mimeType) {
        res.status(400).json({ error: 'Bad Request', message: 'mimeType is required' });
        return;
      }

      const result = await avatarService.generateUploadUrl(getContext(req), req.user.sub, mimeType);
      res.status(200).json({ success: true, data: result });
    } catch (error) {
      if (error instanceof Error && error.message.includes('not allowed')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * POST /me/avatar/complete
   * Complete avatar upload
   */
  router.post('/me/avatar/complete', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const { avatarKey } = req.body;
      if (!avatarKey) {
        res.status(400).json({ error: 'Bad Request', message: 'avatarKey is required' });
        return;
      }

      const avatarInfo = await avatarService.completeUpload(getContext(req), req.user.sub, avatarKey);
      res.status(200).json({ success: true, data: avatarInfo });
    } catch (error) {
      next(error);
    }
  });

  /**
   * DELETE /me/avatar
   * Delete current avatar
   */
  router.delete('/me/avatar', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const { avatarKey } = req.body;
      if (avatarKey) {
        await avatarService.deleteAvatar(getContext(req), avatarKey);
      }

      res.status(200).json({ success: true, message: 'Avatar deleted' });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/avatar/default
   * Get default avatar URL
   */
  router.get('/me/avatar/default', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const name = req.query.name as string;
      const defaultAvatar = avatarService.getDefaultAvatar(name);
      res.status(200).json({ success: true, data: { url: defaultAvatar } });
    } catch (error) {
      next(error);
    }
  });

  // ============ Profile Completion ============

  /**
   * GET /me/completion
   * Get profile completion status
   */
  router.get('/me/completion', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const status = await completionService.calculateCompletion(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: status });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/completion/percentage
   * Get profile completion percentage only
   */
  router.get('/me/completion/percentage', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const percentage = await completionService.getCompletionPercentage(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: { percentage } });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/completion/incomplete
   * Get incomplete sections
   */
  router.get('/me/completion/incomplete', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const sections = await completionService.getIncompleteSections(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: sections });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/completion/missing
   * Get missing required fields
   */
  router.get('/me/completion/missing', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const missing = await completionService.getMissingRequirements(getContext(req), req.user.sub);
      res.status(200).json({ success: true, data: missing });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /me/completion/check
   * Check if profile meets minimum threshold
   */
  router.get('/me/completion/check', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.tenantId || !req.user?.sub) {
        res.status(400).json({ error: 'Bad Request', message: 'Authentication required' });
        return;
      }

      const threshold = parseInt(req.query.threshold as string) || 50;
      const meets = await completionService.meetsMinimumCompletion(getContext(req), req.user.sub, threshold);
      const percentage = await completionService.getCompletionPercentage(getContext(req), req.user.sub);

      res.status(200).json({
        success: true,
        data: {
          meets,
          percentage,
          threshold,
        },
      });
    } catch (error) {
      next(error);
    }
  });

  return router;
}

export default createPreferencesController;
