/**
 * Authentication Controller
 *
 * Express route handlers for authentication endpoints
 */

import { Request, Response } from 'express';
import { authService } from './auth.service';
import { ApiResponse } from '../../shared/types';
import { JwtPayload } from './dtos';

/**
 * Authentication Controller
 */
export class AuthController {
  /**
   * Register new user
   * POST /api/auth/register
   */
  async register(req: Request, res: Response): Promise<void> {
    const result = await authService.register(req.body);

    const response: ApiResponse = {
      success: true,
      data: {
        user: result.user,
        token: result.token,
        refreshToken: result.refreshToken,
        expiresIn: result.expiresIn,
        refreshTokenExpiresIn: result.refreshTokenExpiresIn,
      },
      meta: {
        timestamp: new Date().toISOString(),
        requestId: req.correlationId,
      },
    };

    res.status(201).json(response);
  }

  /**
   * Login user
   * POST /api/auth/login
   */
  async login(req: Request, res: Response): Promise<void> {
    const result = await authService.login(req.body);

    const response: ApiResponse = {
      success: true,
      data: {
        user: result.user,
        token: result.token,
        refreshToken: result.refreshToken,
        expiresIn: result.expiresIn,
        refreshTokenExpiresIn: result.refreshTokenExpiresIn,
      },
      meta: {
        timestamp: new Date().toISOString(),
        requestId: req.correlationId,
      },
    };

    res.status(200).json(response);
  }

  /**
   * Get current user profile
   * GET /api/auth/me
   */
  async getProfile(req: Request, res: Response): Promise<void> {
    const user = req.user as JwtPayload;
    const profile = await authService.getProfile(user.userId);

    const response: ApiResponse = {
      success: true,
      data: profile,
      meta: {
        timestamp: new Date().toISOString(),
        requestId: req.correlationId,
      },
    };

    res.status(200).json(response);
  }

  /**
   * Logout user
   * POST /api/auth/logout
   *
   * Invalidates the access token (blacklists in Redis) and optionally
   * revokes the refresh token.
   */
  async logout(req: Request, res: Response): Promise<void> {
    const authHeader = req.headers.authorization;
    let accessToken = '';

    if (authHeader && authHeader.startsWith('Bearer ')) {
      accessToken = authHeader.substring(7);
    }

    // Get refresh token from request body if provided
    const { refreshToken } = req.body;

    if (accessToken) {
      await authService.logout(accessToken, refreshToken);
    }

    const response: ApiResponse = {
      success: true,
      data: {
        message: 'Logged out successfully',
      },
      meta: {
        timestamp: new Date().toISOString(),
        requestId: req.correlationId,
      },
    };

    res.status(200).json(response);
  }

  /**
   * Refresh access token
   * POST /api/auth/refresh
   *
   * Validates the refresh token and issues a new access token.
   * Also rotates the refresh token for security.
   */
  async refreshToken(req: Request, res: Response): Promise<void> {
    const { refreshToken } = req.body;

    if (!refreshToken) {
      res.status(400).json({
        success: false,
        error: {
          code: 'MISSING_REFRESH_TOKEN',
          message: 'Refresh token is required',
        },
      });
      return;
    }

    const result = await authService.refreshAccessToken(refreshToken);

    const response: ApiResponse = {
      success: true,
      data: {
        token: result.token,
        refreshToken: result.refreshToken,
        expiresIn: result.expiresIn,
        refreshTokenExpiresIn: result.refreshTokenExpiresIn,
      },
      meta: {
        timestamp: new Date().toISOString(),
        requestId: req.correlationId,
      },
    };

    res.status(200).json(response);
  }

  /**
   * Request password reset
   * POST /api/auth/forgot-password
   */
  async forgotPassword(req: Request, res: Response): Promise<void> {
    const { email } = req.body;

    await authService.requestPasswordReset(email);

    // Always return success to prevent email enumeration
    const response: ApiResponse = {
      success: true,
      data: {
        message: 'If an account exists with this email, a password reset link will be sent',
      },
      meta: {
        timestamp: new Date().toISOString(),
        requestId: req.correlationId,
      },
    };

    res.status(200).json(response);
  }

  /**
   * Reset password with token
   * POST /api/auth/reset-password
   */
  async resetPassword(req: Request, res: Response): Promise<void> {
    const { token, newPassword } = req.body;

    await authService.resetPassword(token, newPassword);

    const response: ApiResponse = {
      success: true,
      data: {
        message: 'Password reset successfully',
      },
      meta: {
        timestamp: new Date().toISOString(),
        requestId: req.correlationId,
      },
    };

    res.status(200).json(response);
  }
}

// Export singleton instance
export const authController = new AuthController();
