import express from 'express';
import passport from 'passport';
import { wrapAsync } from '@/api/http/request';
import * as auth from '@/api/controllers/auth.controller';

const router = express.Router();

const authenticated = passport.authenticate('jwt', { session: false });

/**
 * @openapi
 * tags:
 *   - name: Auth
 *     description: >
 *       Cookie-based authentication. Sign-in/refresh set the HttpOnly access and
 *       refresh cookies; sign-out clears them. The public routes (`/signin/local`,
 *       `/refresh`, `/signout`, `/password-reset`, `/signup`, `/verify-email`,
 *       `/send-password-reset-email`, `/email-configured`, OAuth) take no session;
 *       the rest require the access cookie.
 */

/**
 * @openapi
 * /api/auth/signin/local:
 *   post:
 *     tags: [Auth]
 *     summary: Sign in with email + password
 *     description: >
 *       Validates credentials, then sets the access and refresh HttpOnly cookies
 *       and returns the authenticated user profile. Public (no session required).
 *     security: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [email, password]
 *             properties:
 *               email: { type: string }
 *               password: { type: string, format: password }
 *     responses:
 *       200:
 *         description: Signed in; session cookies set.
 *         content:
 *           application/json:
 *             schema: { $ref: '#/components/schemas/UserProfile' }
 *       400: { $ref: '#/components/responses/ValidationError' }
 *       403: { $ref: '#/components/responses/ForbiddenError' }
 */
router.post('/signin/local', wrapAsync(auth.signinLocal));

/**
 * @openapi
 * /api/auth/refresh:
 *   post:
 *     tags: [Auth]
 *     summary: Rotate the session from the refresh cookie
 *     description: >
 *       Reads the refresh cookie, rotates the refresh-token row, re-issues both
 *       cookies, and returns the user profile. Public (uses the cookie, not a
 *       session).
 *     security: []
 *     responses:
 *       200:
 *         description: Session refreshed; new cookies set.
 *         content:
 *           application/json:
 *             schema: { $ref: '#/components/schemas/UserProfile' }
 *       401: { $ref: '#/components/responses/UnauthorizedError' }
 */
router.post('/refresh', wrapAsync(auth.refresh));

/**
 * @openapi
 * /api/auth/signout:
 *   post:
 *     tags: [Auth]
 *     summary: Revoke the session and clear cookies
 *     security: []
 *     responses:
 *       204: { description: Signed out; cookies cleared. }
 */
router.post('/signout', wrapAsync(auth.signout));

/**
 * @openapi
 * /api/auth/me:
 *   get:
 *     tags: [Auth]
 *     summary: Current authenticated user profile
 *     description: Returns the profile (incl. resolved effective `permissions`).
 *     responses:
 *       200:
 *         description: The current user.
 *         content:
 *           application/json:
 *             schema: { $ref: '#/components/schemas/UserProfile' }
 *       401: { $ref: '#/components/responses/UnauthorizedError' }
 */
router.get('/me', authenticated, wrapAsync(auth.me));

/**
 * @openapi
 * /api/auth/password-reset:
 *   put:
 *     tags: [Auth]
 *     summary: Complete a password reset with a token
 *     security: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [token, password]
 *             properties:
 *               token: { type: string }
 *               password: { type: string, format: password }
 *     responses:
 *       200: { description: Password reset. }
 *       400: { $ref: '#/components/responses/ValidationError' }
 */
router.put('/password-reset', wrapAsync(auth.passwordReset));

/**
 * @openapi
 * /api/auth/password-update:
 *   put:
 *     tags: [Auth]
 *     summary: Update the current user's password
 *     responses:
 *       200: { description: Password updated. }
 *       401: { $ref: '#/components/responses/UnauthorizedError' }
 */
router.put('/password-update', authenticated, wrapAsync(auth.passwordUpdate));

/**
 * @openapi
 * /api/auth/send-email-address-verification-email:
 *   post:
 *     tags: [Auth]
 *     summary: Send the current user an email-verification link
 *     responses:
 *       200: { description: Verification email sent (if email is configured). }
 *       401: { $ref: '#/components/responses/UnauthorizedError' }
 */
router.post(
  '/send-email-address-verification-email',
  authenticated,
  wrapAsync(auth.sendEmailVerification),
);

/**
 * @openapi
 * /api/auth/send-password-reset-email:
 *   post:
 *     tags: [Auth]
 *     summary: Send a password-reset email
 *     security: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [email]
 *             properties:
 *               email: { type: string }
 *     responses:
 *       200: { description: Reset email sent (if email is configured). }
 */
router.post('/send-password-reset-email', wrapAsync(auth.sendPasswordResetEmail));

/**
 * @openapi
 * /api/auth/signup:
 *   post:
 *     tags: [Auth]
 *     summary: Self-service signup (template endpoint; gated by product scope)
 *     security: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [email, password]
 *             properties:
 *               email: { type: string }
 *               password: { type: string, format: password }
 *     responses:
 *       200:
 *         description: Signed up; session cookies set.
 *         content:
 *           application/json:
 *             schema: { $ref: '#/components/schemas/UserProfile' }
 *       400: { $ref: '#/components/responses/ValidationError' }
 */
router.post('/signup', wrapAsync(auth.signup));

/**
 * @openapi
 * /api/auth/profile:
 *   put:
 *     tags: [Auth]
 *     summary: Update the current user's own profile
 *     responses:
 *       200:
 *         description: Updated profile.
 *         content:
 *           application/json:
 *             schema: { $ref: '#/components/schemas/UserProfile' }
 *       401: { $ref: '#/components/responses/UnauthorizedError' }
 */
router.put('/profile', authenticated, wrapAsync(auth.updateProfile));

/**
 * @openapi
 * /api/auth/verify-email:
 *   put:
 *     tags: [Auth]
 *     summary: Verify an email address with a token
 *     security: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [token]
 *             properties:
 *               token: { type: string }
 *     responses:
 *       200: { description: Email verified. }
 *       400: { $ref: '#/components/responses/ValidationError' }
 */
router.put('/verify-email', wrapAsync(auth.verifyEmail));

/**
 * @openapi
 * /api/auth/email-configured:
 *   get:
 *     tags: [Auth]
 *     summary: Whether transactional email is configured
 *     security: []
 *     responses:
 *       200:
 *         description: Email-configured flag.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 emailConfigured: { type: boolean }
 */
router.get('/email-configured', auth.emailConfigured);

/**
 * @openapi
 * /api/auth/signin/google:
 *   get:
 *     tags: [Auth]
 *     summary: Begin Google OAuth sign-in (redirect)
 *     security: []
 *     responses:
 *       302: { description: Redirect to Google. }
 */
router.get('/signin/google', auth.googleSignin);

/**
 * @openapi
 * /api/auth/signin/google/callback:
 *   get:
 *     tags: [Auth]
 *     summary: Google OAuth callback — sets cookies, redirects to the UI
 *     security: []
 *     responses:
 *       302: { description: Redirect to the UI with session cookies set. }
 */
router.get(
  '/signin/google/callback',
  passport.authenticate('google', { failureRedirect: '/login', session: false }),
  wrapAsync(auth.googleCallback),
);

export default router;
