/**
 * Authentication Routes for Redirect Intelligence v2
 * 
 * Handles user login, registration, logout, and profile management
 */

import express from 'express';
import { z } from 'zod';
import rateLimit from 'express-rate-limit';
import { AuthService } from '../services/auth.service';
import { requireAuth, AuthenticatedRequest } from '../middleware/auth.middleware';
import { logger } from '../lib/logger';

const router = express.Router();
const authService = new AuthService();

// Rate limiting for auth endpoints
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 requests per windowMs
  message: {
    success: false,
    error: 'Too many authentication attempts',
    message: 'Please try again later'
  },
  standardHeaders: true,
  legacyHeaders: false,
});

const registerLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 3, // limit each IP to 3 registration attempts per hour
  message: {
    success: false,
    error: 'Too many registration attempts',
    message: 'Please try again later'
  },
});

// Input validation schemas
const loginSchema = z.object({
  email: z.string().email('Invalid email address'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
});

const registerSchema = z.object({
  email: z.string().email('Invalid email address'),
  name: z.string().min(2, 'Name must be at least 2 characters'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
  organizationName: z.string().min(2, 'Organization name must be at least 2 characters').optional(),
});

/**
 * POST /api/v1/auth/login
 * Authenticate user with email and password
 */
router.post('/login', authLimiter, async (req, res) => {
  try {
    // Validate input
    const validatedData = loginSchema.parse(req.body);

    // Attempt login
    const { user, token } = await authService.login(validatedData);

    // Set HttpOnly cookie
    res.cookie('auth_token', token, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
      path: '/',
    });

    // Log successful login
    logger.info(`Successful login: ${user.email}`);

    res.json({
      success: true,
      status: 200,
      data: {
        user,
        token, // Also return token for API clients
      },
      message: 'Login successful'
    });

  } catch (error) {
    logger.warn('Login failed:', error);

    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Validation error',
        message: error.errors[0]?.message || 'Invalid input',
        details: error.errors
      });
    }

    res.status(400).json({
      success: false,
      error: 'Login failed',
      message: error instanceof Error ? error.message : 'Invalid credentials'
    });
  }
});

/**
 * POST /api/v1/auth/register
 * Register a new user account
 */
router.post('/register', registerLimiter, async (req, res) => {
  try {
    // Validate input
    const validatedData = registerSchema.parse(req.body);

    // Create user
    const user = await authService.register(validatedData);

    // Log successful registration
    logger.info(`New user registered: ${user.email}`);

    res.status(201).json({
      success: true,
      status: 201,
      data: { user },
      message: 'Registration successful'
    });

  } catch (error) {
    logger.warn('Registration failed:', error);

    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Validation error',
        message: error.errors[0]?.message || 'Invalid input',
        details: error.errors
      });
    }

    const statusCode = error instanceof Error && error.message === 'User already exists' ? 409 : 400;

    res.status(statusCode).json({
      success: false,
      error: 'Registration failed',
      message: error instanceof Error ? error.message : 'Registration failed'
    });
  }
});

/**
 * POST /api/v1/auth/logout
 * Clear authentication tokens
 */
router.post('/logout', (req, res) => {
  // Clear cookie
  res.clearCookie('auth_token', {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    path: '/',
  });

  logger.info('User logged out');

  res.json({
    success: true,
    status: 200,
    message: 'Logout successful'
  });
});

/**
 * GET /api/v1/auth/me
 * Get current user profile
 */
router.get('/me', requireAuth, (req: AuthenticatedRequest, res) => {
  res.json({
    success: true,
    status: 200,
    data: {
      user: req.user
    }
  });
});

/**
 * PUT /api/v1/auth/me
 * Update current user profile
 */
router.put('/me', requireAuth, async (req: AuthenticatedRequest, res) => {
  try {
    const updateSchema = z.object({
      name: z.string().min(2).optional(),
      email: z.string().email().optional(),
    });

    const validatedData = updateSchema.parse(req.body);

    // Update user profile (simplified - would need more validation in production)
    // This is a placeholder for Phase 1
    logger.info(`Profile update requested by user: ${req.user!.email}`);

    res.json({
      success: true,
      status: 200,
      data: {
        user: req.user
      },
      message: 'Profile update will be implemented in a future phase'
    });

  } catch (error) {
    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Validation error',
        message: error.errors[0]?.message || 'Invalid input',
        details: error.errors
      });
    }

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

/**
 * POST /api/v1/auth/refresh
 * Refresh authentication token
 */
router.post('/refresh', requireAuth, (req: AuthenticatedRequest, res) => {
  try {
    // Generate new token
    const token = authService.generateToken(req.user!.id, req.user!.email);

    // Set new cookie
    res.cookie('auth_token', token, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
      path: '/',
    });

    res.json({
      success: true,
      status: 200,
      data: { token },
      message: 'Token refreshed successfully'
    });

  } catch (error) {
    logger.error('Token refresh failed:', error);
    res.status(500).json({
      success: false,
      error: 'Refresh failed',
      message: 'Failed to refresh token'
    });
  }
});

export default router;
