import { Router } from 'express';
import { zeroTrustAuthMiddleware, type AuthenticatedRequest } from '../middleware/auth.middleware';
import { portalAuthService } from '../services/portal-auth.service';
import { logger } from '@/infrastructure/monitoring/logger';
import { DbisError, ErrorCode } from '@/shared/types';
import { validateRequest, authValidationSchemas } from '../middleware/validation.middleware';
import { requireAdminPermission } from '../middleware/admin-permission.middleware';
import { AdminPermission } from '@/core/admin/shared/permissions.constants';

const router = Router();

function handleAuthRouteError(error: unknown, res: any, fallbackStatus = 400) {
  if (error instanceof DbisError) {
    return res.status(error.code === ErrorCode.FORBIDDEN ? 403 : 401).json({
      success: false,
      error: {
        code: error.code,
        message: error.message,
      },
      timestamp: new Date(),
    });
  }

  const message = error instanceof Error ? error.message : 'Unexpected error';
  const status = /not found/i.test(message)
    ? 404
    : /locked|expired|pending|invalid|incorrect|required|configured/i.test(message)
    ? 400
    : fallbackStatus;

  return res.status(status).json({
    success: false,
    error: {
      code: status === 404 ? ErrorCode.NOT_FOUND : ErrorCode.VALIDATION_ERROR,
      message,
    },
    timestamp: new Date(),
  });
}

router.post(
  '/login',
  validateRequest({ body: authValidationSchemas.loginRequest }),
  async (req, res, next) => {
    try {
      const { username, password, otp, surface } = req.body || {};
      const result = await portalAuthService.login({
        username,
        password,
        otp,
        surface,
      });

      res.json(result);
    } catch (error) {
      if (error instanceof DbisError) {
        return next(error);
      }
      logger.warn('Portal login rejected', {
        surface: req.body?.surface || 'admin',
        username: req.body?.username,
        error: error instanceof Error ? error.message : String(error),
      });
      return res.status(401).json({
        success: false,
        error: {
          code: ErrorCode.UNAUTHORIZED,
          message: error instanceof Error ? error.message : 'Invalid credentials',
        },
        timestamp: new Date(),
      });
    }
  }
);

router.get('/me', zeroTrustAuthMiddleware, async (req: AuthenticatedRequest, res) => {
  res.json({
    user: portalAuthService.buildPortalUserFromClaims({
      employeeId: req.employeeId,
      email: req.email,
      name: req.name,
      roleName: req.roleName,
      permissions: req.permissions,
      sovereignBankId: req.sovereignBankId,
      identityType: req.identityType || 'WEB_PORTAL',
      sessionType: req.sessionType || 'portal',
      portalSurface: req.portalSurface,
      apiRole: req.apiRole,
    }),
  });
});

router.post('/logout', zeroTrustAuthMiddleware, async (_req, res) => {
  res.status(204).send();
});

router.post(
  '/password/change',
  zeroTrustAuthMiddleware,
  validateRequest({ body: authValidationSchemas.passwordChangeRequest }),
  async (req: AuthenticatedRequest, res) => {
    try {
      await portalAuthService.changePassword({
        portalSurface: req.portalSurface,
        employeeId: req.employeeId,
        currentPassword: req.body.currentPassword,
        newPassword: req.body.newPassword,
      });
      return res.status(204).send();
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.post(
  '/password/reset/request',
  validateRequest({ body: authValidationSchemas.passwordResetRequest }),
  async (req, res) => {
    logger.info('Portal password reset requested', {
      username: req.body.username,
      surface: req.body.surface || 'admin',
    });

    return res.json({
      success: true,
      message: 'Password reset request recorded for administrator review',
    });
  }
);

router.post(
  '/password/reset/complete',
  validateRequest({ body: authValidationSchemas.passwordResetCompleteRequest }),
  async (req, res) => {
    try {
      await portalAuthService.completePasswordReset({
        username: req.body.username,
        resetToken: req.body.resetToken,
        newPassword: req.body.newPassword,
        surface: req.body.surface,
      });

      return res.status(204).send();
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.get('/mfa/status', zeroTrustAuthMiddleware, async (req: AuthenticatedRequest, res) => {
  try {
    if (!req.employeeId || req.portalSurface === 'member') {
      throw new Error('MFA is only available for employee portal accounts');
    }

    const status = await portalAuthService.getEmployeeMfaStatus(req.employeeId);
    return res.json(status);
  } catch (error) {
    return handleAuthRouteError(error, res);
  }
});

router.post('/mfa/setup', zeroTrustAuthMiddleware, async (req: AuthenticatedRequest, res) => {
  try {
    if (!req.employeeId || req.portalSurface === 'member') {
      throw new Error('MFA is only available for employee portal accounts');
    }

    const enrollment = await portalAuthService.beginEmployeeMfaEnrollment(req.employeeId);
    return res.json(enrollment);
  } catch (error) {
    return handleAuthRouteError(error, res);
  }
});

router.post(
  '/mfa/enable',
  zeroTrustAuthMiddleware,
  validateRequest({ body: authValidationSchemas.mfaSetupEnableRequest }),
  async (req: AuthenticatedRequest, res) => {
    try {
      if (!req.employeeId || req.portalSurface === 'member') {
        throw new Error('MFA is only available for employee portal accounts');
      }

      await portalAuthService.enableEmployeeMfa(req.employeeId, req.body.secret, req.body.otp);
      return res.status(204).send();
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.post(
  '/mfa/disable',
  zeroTrustAuthMiddleware,
  validateRequest({ body: authValidationSchemas.mfaDisableRequest }),
  async (req: AuthenticatedRequest, res) => {
    try {
      if (!req.employeeId || req.portalSurface === 'member') {
        throw new Error('MFA is only available for employee portal accounts');
      }

      await portalAuthService.disableEmployeeMfa(req.employeeId, req.body.otp);
      return res.status(204).send();
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.post(
  '/admin/accounts/employee',
  zeroTrustAuthMiddleware,
  requireAdminPermission(AdminPermission.RBAC_EDIT),
  validateRequest({ body: authValidationSchemas.issueEmployeeAccountRequest }),
  async (req: AuthenticatedRequest, res) => {
    try {
      const issued = await portalAuthService.issueEmployeeAccount(req.body);
      return res.status(201).json(issued);
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.get(
  '/admin/accounts/member',
  zeroTrustAuthMiddleware,
  requireAdminPermission(AdminPermission.RBAC_EDIT),
  async (req, res) => {
    try {
      const memberAccounts = await portalAuthService.listMemberAccounts({
        approvalStatus:
          typeof req.query.approvalStatus === 'string' ? req.query.approvalStatus : undefined,
        participantId:
          typeof req.query.participantId === 'string' ? req.query.participantId : undefined,
      });
      return res.json(memberAccounts);
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.post(
  '/admin/accounts/member',
  zeroTrustAuthMiddleware,
  requireAdminPermission(AdminPermission.RBAC_EDIT),
  validateRequest({ body: authValidationSchemas.issueMemberAccountRequest }),
  async (req: AuthenticatedRequest, res) => {
    try {
      const issued = await portalAuthService.issueMemberAccount(req.body);
      return res.status(201).json(issued);
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.post(
  '/admin/accounts/member/:memberId/approve',
  zeroTrustAuthMiddleware,
  requireAdminPermission(AdminPermission.RBAC_EDIT),
  async (req: AuthenticatedRequest, res) => {
    try {
      if (!req.employeeId) {
        throw new Error('Employee identity required');
      }

      await portalAuthService.approveMemberAccount(req.params.memberId, req.employeeId);
      return res.status(204).send();
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.post(
  '/admin/password-reset/issue',
  zeroTrustAuthMiddleware,
  requireAdminPermission(AdminPermission.RBAC_EDIT),
  validateRequest({ body: authValidationSchemas.issueResetTokenRequest }),
  async (req, res) => {
    try {
      const token = await portalAuthService.issuePasswordResetToken(req.body);
      return res.status(201).json(token);
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

router.post(
  '/admin/accounts/deactivate',
  zeroTrustAuthMiddleware,
  requireAdminPermission(AdminPermission.RBAC_EDIT),
  validateRequest({ body: authValidationSchemas.deactivateAccountRequest }),
  async (req, res) => {
    try {
      await portalAuthService.deactivateAccount(req.body);
      return res.status(204).send();
    } catch (error) {
      return handleAuthRouteError(error, res);
    }
  }
);

export default router;
