/**
 * User Controller
 *
 * HTTP request handlers for user profile endpoints
 */

import { Request, Response } from 'express';
import { userService } from './user.service';
import { ValidationError, NotFoundError, AuthenticationError, ConflictError } from '../../shared/types';
import { logger } from '../../shared/utils/logger';
import type { UserRole } from '@prisma/client';

// ============================================
// CONTROLLER
// ============================================

class UserController {
  /**
   * GET /api/users/me
   * Get current user profile
   */
  async getProfile(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.userId;

      if (!userId) {
        throw new AuthenticationError('User authentication required');
      }

      const user = await userService.getUserProfile(userId);

      res.json({
        success: true,
        data: user,
      });
    } catch (error) {
      logger.error({ error, req }, 'Error getting user profile');

      if (error instanceof AuthenticationError) {
        res.status(401).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      if (error instanceof NotFoundError) {
        res.status(404).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: { code: 'INTERNAL_ERROR', message: 'Failed to get profile' },
      });
    }
  }

  /**
   * PUT /api/users/me
   * Update current user profile
   */
  async updateProfile(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.userId;

      if (!userId) {
        throw new AuthenticationError('User authentication required');
      }

      const { username, telegramChatId } = req.body;

      const updatedUser = await userService.updateProfile(userId, {
        username,
        telegramChatId: telegramChatId || null,
      });

      res.json({
        success: true,
        data: updatedUser,
      });
    } catch (error) {
      logger.error({ error, req }, 'Error updating user profile');

      if (error instanceof AuthenticationError) {
        res.status(401).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      if (error instanceof ValidationError) {
        res.status(400).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      if (error instanceof ConflictError) {
        res.status(409).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: { code: 'INTERNAL_ERROR', message: 'Failed to update profile' },
      });
    }
  }

  /**
   * GET /api/users/me/stats
   * Get current user statistics
   */
  async getStats(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.userId;

      if (!userId) {
        throw new AuthenticationError('User authentication required');
      }

      const stats = await userService.getUserStats(userId);

      res.json({
        success: true,
        data: stats,
      });
    } catch (error) {
      logger.error({ error, req }, 'Error getting user stats');

      if (error instanceof AuthenticationError) {
        res.status(401).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: { code: 'INTERNAL_ERROR', message: 'Failed to get stats' },
      });
    }
  }

  /**
   * PUT /api/users/me/password
   * Change current user password
   */
  async changePassword(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.userId;

      if (!userId) {
        throw new AuthenticationError('User authentication required');
      }

      const { currentPassword, newPassword } = req.body;

      await userService.changePassword(userId, currentPassword, newPassword);

      res.json({
        success: true,
        message: 'Password changed successfully',
      });
    } catch (error) {
      logger.error({ error, req }, 'Error changing password');

      if (error instanceof AuthenticationError) {
        res.status(401).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      if (error instanceof ValidationError) {
        res.status(400).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: { code: 'INTERNAL_ERROR', message: 'Failed to change password' },
      });
    }
  }

  /**
   * GET /api/users (admin only)
   * List all users
   */
  async listUsers(req: Request, res: Response): Promise<void> {
    try {
      const { role, isActive, page = '1', limit = '50' } = req.query;

      const result = await userService.listUsers({
        role: role as UserRole,
        isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
        page: parseInt(page as string, 10) || 1,
        limit: parseInt(limit as string, 10) || 50,
      });

      res.json({
        success: true,
        data: result.users,
        meta: {
          pagination: {
            page: parseInt(page as string, 10) || 1,
            limit: parseInt(limit as string, 10) || 50,
            total: result.total,
            totalPages: Math.ceil(result.total / (parseInt(limit as string, 10) || 50)),
          },
        },
      });
    } catch (error) {
      logger.error({ error, req }, 'Error listing users');

      res.status(500).json({
        success: false,
        error: { code: 'INTERNAL_ERROR', message: 'Failed to list users' },
      });
    }
  }

  /**
   * PUT /api/users/:id/role (admin only)
   * Update user role
   */
  async updateUserRole(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const { role } = req.body;

      if (!role || !['STUDENT', 'TEACHER', 'ADMIN'].includes(role)) {
        throw new ValidationError('Valid role is required (STUDENT, TEACHER, ADMIN)');
      }

      const updatedUser = await userService.updateUserRole(id, role as UserRole);

      res.json({
        success: true,
        data: updatedUser,
      });
    } catch (error) {
      logger.error({ error, req }, 'Error updating user role');

      if (error instanceof ValidationError) {
        res.status(400).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      if (error instanceof NotFoundError) {
        res.status(404).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: { code: 'INTERNAL_ERROR', message: 'Failed to update user role' },
      });
    }
  }

  /**
   * DELETE /api/users/:id (admin only)
   * Deactivate user
   */
  async deactivateUser(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;

      const deactivatedUser = await userService.deactivateUser(id);

      res.json({
        success: true,
        data: deactivatedUser,
        message: 'User deactivated successfully',
      });
    } catch (error) {
      logger.error({ error, req }, 'Error deactivating user');

      if (error instanceof NotFoundError) {
        res.status(404).json({
          success: false,
          error: { code: error.code, message: error.message },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: { code: 'INTERNAL_ERROR', message: 'Failed to deactivate user' },
      });
    }
  }
}

// ============================================
// EXPORT
// ============================================

export const userController = new UserController();
export default userController;