import { Request, Response } from 'express';
import { z } from 'zod';

import { getErrorMessage } from '../../utils/error-utils';

import { mfaService } from './mfa.service';

const VerifyTOTPDto = z.object({
  token: z.string().length(6),
});

/**
 * EN: MFA Controller
 * VI: Controller MFA
 */
export class MFAController {
  /**
   * EN: Enable TOTP
   * VI: Bật TOTP
   */
  async enableTOTP(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user?.id || (req as any).user?.sub;
      
      if (!userId) {
        res.status(401).json({
          success: false,
          error: { code: 'UNAUTHORIZED', message: 'Authentication required' },
        });
        return;
      }

      const result = await mfaService.enableTOTP(userId);

      res.json({
        success: true,
        data: {
          secret: result.secret,
          qrCodeUrl: result.qrCodeUrl,
          message: 'Scan QR code with authenticator app and verify with token',
        },
      });
    } catch (error: unknown) {
      res.status(500).json({
        success: false,
        error: {
          code: 'ENABLE_TOTP_FAILED',
          message: getErrorMessage(error) || 'Failed to enable TOTP',
        },
      });
    }
  }

  /**
   * EN: Verify and enable TOTP
   * VI: Xác thực và bật TOTP
   */
  async verifyAndEnableTOTP(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user?.id || (req as any).user?.sub;
      const data = VerifyTOTPDto.parse(req.body);
      const { secret } = req.body;

      if (!userId || !secret) {
        res.status(400).json({
          success: false,
          error: { code: 'INVALID_INPUT', message: 'userId and secret required' },
        });
        return;
      }

      const verified = await mfaService.verifyAndEnableTOTP(userId, secret, data.token);

      if (verified) {
        res.json({
          success: true,
          data: { message: 'TOTP enabled successfully' },
        });
      } else {
        res.status(400).json({
          success: false,
          error: { code: 'INVALID_TOKEN', message: 'Invalid TOTP token' },
        });
      }
    } catch (error: unknown) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid input',
            details: error.issues,
          },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: {
          code: 'VERIFY_TOTP_FAILED',
          message: getErrorMessage(error) || 'Failed to verify TOTP',
        },
      });
    }
  }

  /**
   * EN: Verify TOTP token
   * VI: Xác thực token TOTP
   */
  async verifyTOTP(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user?.id || (req as any).user?.sub;
      const data = VerifyTOTPDto.parse(req.body);

      if (!userId) {
        res.status(401).json({
          success: false,
          error: { code: 'UNAUTHORIZED', message: 'Authentication required' },
        });
        return;
      }

      const verified = await mfaService.verifyTOTP(userId, data.token);

      if (verified) {
        res.json({
          success: true,
          data: { verified: true, message: 'TOTP verified successfully' },
        });
      } else {
        res.status(400).json({
          success: false,
          error: { code: 'INVALID_TOKEN', message: 'Invalid TOTP token' },
        });
      }
    } catch (error: unknown) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid input',
            details: error.issues,
          },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: {
          code: 'VERIFY_TOTP_FAILED',
          message: getErrorMessage(error) || 'Failed to verify TOTP',
        },
      });
    }
  }

  /**
   * EN: Disable MFA
   * VI: Tắt MFA
   */
  async disableMFA(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user?.id || (req as any).user?.sub;

      if (!userId) {
        res.status(401).json({
          success: false,
          error: { code: 'UNAUTHORIZED', message: 'Authentication required' },
        });
        return;
      }

      await mfaService.disableMFA(userId);

      res.json({
        success: true,
        data: { message: 'MFA disabled successfully' },
      });
    } catch (error: unknown) {
      res.status(500).json({
        success: false,
        error: {
          code: 'DISABLE_MFA_FAILED',
          message: getErrorMessage(error) || 'Failed to disable MFA',
        },
      });
    }
  }

  /**
   * EN: Get MFA devices
   * VI: Lấy thiết bị MFA
   */
  async getMFADevices(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user?.id || (req as any).user?.sub;

      if (!userId) {
        res.status(401).json({
          success: false,
          error: { code: 'UNAUTHORIZED', message: 'Authentication required' },
        });
        return;
      }

      const devices = await mfaService.getUserMFADevices(userId);

      res.json({
        success: true,
        data: devices.map(d => ({
          id: d.id,
          type: d.type,
          name: d.name,
          lastUsedAt: d.lastUsedAt,
          createdAt: d.createdAt,
        })),
      });
    } catch (error: unknown) {
      res.status(500).json({
        success: false,
        error: {
          code: 'GET_MFA_DEVICES_FAILED',
          message: getErrorMessage(error) || 'Failed to get MFA devices',
        },
      });
    }
  }
}

export const mfaController = new MFAController();
