const express = require('express')
const router = new express.Router()
const { body, validationResult } = require('express-validator')
const debug = require('debug')('48hr-email:auth-routes')
const { redirectIfAuthenticated } = require('../middleware/auth')
const config = require('../../../application/config-service')
const templateContext = require('../template-context')

// Simple in-memory rate limiters for registration and login
const registrationRateLimitStore = new Map()
const loginRateLimitStore = new Map()

// Registration rate limiter: 5 attempts per IP per hour
const registrationRateLimiter = (req, res, next) => {
    const ip = req.ip || req.connection.remoteAddress
    const now = Date.now()
    const windowMs = 60 * 60 * 1000 // 1 hour
    const maxRequests = 5

    // Clean up old entries
    for (const [key, data] of registrationRateLimitStore.entries()) {
        if (now - data.resetTime > windowMs) {
            registrationRateLimitStore.delete(key)
        }
    }

    // Get or create entry for this IP
    let ipData = registrationRateLimitStore.get(ip)
    if (!ipData || now - ipData.resetTime > windowMs) {
        ipData = { count: 0, resetTime: now }
        registrationRateLimitStore.set(ip, ipData)
    }

    // Check if limit exceeded
    if (ipData.count >= maxRequests) {
        debug(`Registration rate limit exceeded for IP ${ip}`)
        req.session.errorMessage = 'Too many registration attempts. Please try again after 1 hour.'
        return res.redirect('/register')
    }

    // Increment counter
    ipData.count++
        next()
}

// Login rate limiter: 10 attempts per IP per 15 minutes
const loginRateLimiter = (req, res, next) => {
    const ip = req.ip || req.connection.remoteAddress
    const now = Date.now()
    const windowMs = 15 * 60 * 1000 // 15 minutes
    const maxRequests = 10

    // Clean up old entries
    for (const [key, data] of loginRateLimitStore.entries()) {
        if (now - data.resetTime > windowMs) {
            loginRateLimitStore.delete(key)
        }
    }

    // Get or create entry for this IP
    let ipData = loginRateLimitStore.get(ip)
    if (!ipData || now - ipData.resetTime > windowMs) {
        ipData = { count: 0, resetTime: now }
        loginRateLimitStore.set(ip, ipData)
    }

    // Check if limit exceeded
    if (ipData.count >= maxRequests) {
        debug(`Login rate limit exceeded for IP ${ip}`)
        req.session.errorMessage = 'Too many login attempts. Please try again after 15 minutes.'
        return res.redirect('/login')
    }

    // Increment counter
    ipData.count++
        next()
}

// Middleware to capture redirect URL
router.use((req, res, next) => {
    if (req.method === 'GET' && req.path === '/auth') {
        const referer = req.get('Referer')
        const redirectParam = req.query.redirect
        const redirectUrl = redirectParam || (referer && !referer.includes('/auth') ? referer : null)

        if (redirectUrl) {
            req.session.redirectAfterLogin = redirectUrl
        }
    }
    next()
})

// GET /auth - Show unified auth page (login or register)
router.get('/auth', redirectIfAuthenticated, (req, res) => {
    const config = req.app.get('config')
    const successMessage = req.session.successMessage
    delete req.session.successMessage

    res.render('auth', templateContext.build(req, {
        title: `Login or Register | ${(config.http.features.branding || ['48hr.email'])[0]}`,
        successMessage
    }))
})

// POST /register - Process registration
router.post('/register',
    redirectIfAuthenticated,
    registrationRateLimiter,
    body('username').trim().notEmpty().withMessage('Username is required'),
    body('password').notEmpty().withMessage('Password is required'),
    body('confirmPassword').notEmpty().withMessage('Password confirmation is required'),
    async(req, res) => {
        try {
            const errors = validationResult(req)
            if (!errors.isEmpty()) {
                const firstError = errors.array()[0].msg
                debug(`Registration validation failed: ${firstError}`)
                req.session.errorMessage = firstError
                return res.redirect('/auth')
            }

            const { username, password, confirmPassword } = req.body

            // Check if passwords match
            if (password !== confirmPassword) {
                debug('Registration failed: Passwords do not match')
                req.session.errorMessage = 'Passwords do not match'
                return res.redirect('/auth')
            }

            const authService = req.app.get('authService')
            const result = await authService.register(username, password)

            if (result.success) {
                debug(`User registered successfully: ${username}`)
                req.session.successMessage = 'Registration successful! Please log in.'
                return res.redirect('/auth')
            } else {
                debug(`Registration failed: ${result.error}`)
                req.session.errorMessage = result.error
                return res.redirect('/auth')
            }
        } catch (error) {
            debug(`Registration error: ${error.message}`)
            console.error('Error during registration', error)
            req.session.errorMessage = 'An unexpected error occurred. Please try again.'
            res.redirect('/auth')
        }
    }
)

// POST /login - Process login
router.post('/login',
    redirectIfAuthenticated,
    loginRateLimiter,
    body('username').trim().notEmpty().withMessage('Username is required'),
    body('password').notEmpty().withMessage('Password is required'),
    async(req, res) => {
        try {
            const errors = validationResult(req)
            if (!errors.isEmpty()) {
                const firstError = errors.array()[0].msg
                debug(`Login validation failed: ${firstError}`)
                req.session.errorMessage = firstError
                return res.redirect('/auth')
            }

            const { username, password } = req.body
            const authService = req.app.get('authService')
            const result = await authService.login(username, password)

            if (result.success) {
                debug(`User logged in successfully: ${username}`)

                // Store redirect URL before regenerating session
                const redirectUrl = req.session.redirectAfterLogin || '/'

                // Regenerate session to prevent fixation attacks
                req.session.regenerate((err) => {
                    if (err) {
                        debug(`Session regeneration error: ${err.message}`)
                        req.session.errorMessage = 'Login failed. Please try again.'
                        return res.redirect('/auth')
                    }

                    // Set session data
                    req.session.userId = result.user.id
                    req.session.username = result.user.username
                    req.session.isAuthenticated = true
                    req.session.createdAt = result.user.created_at

                    req.session.save((err) => {
                        if (err) {
                            debug(`Session save error: ${err.message}`)
                            req.session.errorMessage = 'Login failed. Please try again.'
                            return res.redirect('/auth')
                        }

                        debug(`Session created for user: ${username}, redirecting to: ${redirectUrl}`)
                        res.redirect(redirectUrl)
                    })
                })
            } else {
                debug(`Login failed: ${result.error}`)
                req.session.errorMessage = result.error
                return res.redirect('/auth')
            }
        } catch (error) {
            debug(`Login error: ${error.message}`)
            console.error('Error during login', error)
            req.session.errorMessage = 'An unexpected error occurred. Please try again.'
            res.redirect('/auth')
        }
    }
)

// GET /logout - Logout user
router.get('/logout', (req, res) => {
        // Store redirect URL before destroying session
        const redirectUrl = req.query.redirect || req.get('Referer') || '/'

        debug(`Logout requested with redirect: ${redirectUrl}`)

        if (req.session) {
            const username = req.session.username
            req.session.destroy((err) => {
                if (err) {
                    debug(`Logout error: ${err.message}`)
                    console.error('Error during logout', err)
                    return res.redirect('/')
                }

                debug(`User logged out: ${username}, redirecting to: ${redirectUrl}`)
                    // Clear cookie explicitly
                res.clearCookie('connect.sid')
                res.redirect(redirectUrl)
            })
        } else {
            debug(`No session found, redirecting to: ${redirectUrl}`)
            res.redirect(redirectUrl)
        }
    }) // GET /auth/check - JSON endpoint for checking auth status (AJAX)
router.get('/auth/check', (req, res) => {
    if (req.session && req.session.userId && req.session.isAuthenticated) {
        res.json({
            authenticated: true,
            user: {
                id: req.session.userId,
                username: req.session.username
            }
        })
    } else {
        res.json({
            authenticated: false
        })
    }
})

module.exports = router
