import { Router } from 'express'
import { z } from 'zod'
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import crypto from 'crypto'
import { prisma } from '../lib/prisma'
import { sendTransactionalEmail } from '../services/notificationService'

const router = Router()

const RESET_TOKEN_TTL_MINUTES = 60

function signEmployeeToken(employeeId: string) {
  return jwt.sign(
    { sub: employeeId, type: 'employee' },
    process.env.JWT_SECRET!,
    { expiresIn: (process.env.JWT_EXPIRY ?? '8h') as jwt.SignOptions['expiresIn'] },
  )
}

function buildResetEmailHtml(resetUrl: string, firstName: string) {
  return `
    <p>Hi ${firstName},</p>
    <p>You requested a password reset for your RentalDriveGo workspace account.</p>
    <p><a href="${resetUrl}" style="background:#1d4ed8;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:600;">Reset your password</a></p>
    <p>This link expires in ${RESET_TOKEN_TTL_MINUTES} minutes. If you did not request this, you can safely ignore this email.</p>
    <p>RentalDriveGo</p>
  `
}

router.post('/login', async (req, res, next) => {
  try {
    const { email, password } = z.object({
      email: z.string().email().max(255).trim().toLowerCase(),
      password: z.string().max(128),
    }).parse(req.body)

    const employee = await prisma.employee.findFirst({
      where: { email },
      include: { company: true },
    })

    if (!employee || !employee.isActive) {
      return res.status(401).json({ error: 'invalid_credentials', message: 'Invalid email or password', statusCode: 401 })
    }

    if (!employee.passwordHash) {
      return res.status(401).json({ error: 'password_not_set', message: 'This account does not have a password yet. Use the invitation or reset email to set one first.', statusCode: 401 })
    }

    const valid = await bcrypt.compare(password, employee.passwordHash)
    if (!valid) {
      return res.status(401).json({ error: 'invalid_credentials', message: 'Invalid email or password', statusCode: 401 })
    }

    const token = signEmployeeToken(employee.id)

    res.json({
      data: {
        token,
        employee: {
          id: employee.id,
          email: employee.email,
          firstName: employee.firstName,
          lastName: employee.lastName,
          role: employee.role,
          companyId: employee.companyId,
          companyName: employee.company.name,
          companySlug: employee.company.slug,
        },
      },
    })
  } catch (err) { next(err) }
})

router.post('/forgot-password', async (req, res, next) => {
  try {
    const { email } = z.object({ email: z.string().email().max(255).trim().toLowerCase() }).parse(req.body)

    // Always return success to avoid user enumeration
    const employee = await prisma.employee.findFirst({ where: { email, isActive: true } })
    if (employee) {
      const rawToken = crypto.randomBytes(32).toString('hex')
      const expiresAt = new Date(Date.now() + RESET_TOKEN_TTL_MINUTES * 60 * 1000)

      await prisma.employee.update({
        where: { id: employee.id },
        data: { passwordResetToken: rawToken, passwordResetExpiresAt: expiresAt },
      })

      const dashboardUrl = process.env.DASHBOARD_URL ?? 'http://localhost:3001'
      const resetUrl = `${dashboardUrl}/reset-password?token=${rawToken}`

      await sendTransactionalEmail({
        to: email,
        subject: 'Reset your RentalDriveGo password',
        html: buildResetEmailHtml(resetUrl, employee.firstName),
        text: `Hi ${employee.firstName},\n\nReset your password here: ${resetUrl}\n\nThis link expires in ${RESET_TOKEN_TTL_MINUTES} minutes.\n\nRentalDriveGo`,
      }).catch((err) => console.error('[ForgotPassword] Email send failed:', err?.message))
    }

    res.json({ data: { message: 'If that email is registered, a reset link has been sent.' } })
  } catch (err) { next(err) }
})

router.post('/reset-password', async (req, res, next) => {
  try {
    const { token, password } = z.object({
      token: z.string().min(1),
      password: z.string().min(8).max(128),
    }).parse(req.body)

    const employee = await prisma.employee.findFirst({
      where: {
        passwordResetToken: token,
        passwordResetExpiresAt: { gt: new Date() },
      },
    })

    if (!employee) {
      return res.status(400).json({ error: 'invalid_token', message: 'Reset link is invalid or has expired.', statusCode: 400 })
    }

    const passwordHash = await bcrypt.hash(password, 12)

    await prisma.employee.update({
      where: { id: employee.id },
      data: {
        passwordHash,
        passwordResetToken: null,
        passwordResetExpiresAt: null,
      },
    })

    res.json({ data: { message: 'Password updated successfully. You can now sign in.' } })
  } catch (err) { next(err) }
})

export default router
