import { Request, Response } from 'express';
import jwt = require('jsonwebtoken');
import { prisma } from '../config/database';
import { generateOtp } from '../utils/otp';
import { sendOtpEmail } from '../config/mailer';
import { AuthRequest } from '../middleware/auth';

const JWT_SECRET = process.env['JWT_SECRET'] || 'dev-secret';

export async function sendOtp(req: Request, res: Response): Promise<void> {
  try {
    const { email } = req.body;

    if (!email || typeof email !== 'string') {
      res.status(400).json({ error: 'Valid email is required' });
      return;
    }

    const normalized = email.trim().toLowerCase();

    const allowed = await prisma.allowedEmail.findUnique({ where: { email: normalized } });
    if (!allowed || !allowed.isActive) {
      res.status(403).json({ error: 'This email is not authorized to access the portal. Please contact your super admin.' });
      return;
    }

    const otp = generateOtp();

    // Invalidate old OTPs for this email
    await prisma.otpToken.updateMany({
      where: { email: normalized, used: false },
      data: { used: true },
    });

    // Create new OTP token (expires in 10 minutes)
    await prisma.otpToken.create({
      data: {
        email: normalized,
        otp,
        expiresAt: new Date(Date.now() + 10 * 60 * 1000),
      },
    });

    await sendOtpEmail(normalized, otp);

    const exposeOtp = process.env['EXPOSE_OTP_IN_RESPONSE'] === 'true';
    res.json({
      message: 'OTP sent successfully',
      ...(exposeOtp ? { devOtp: otp } : {}),
    });
  } catch (error) {
    console.error('sendOtp error:', error);
    res.status(500).json({ error: 'Failed to send OTP' });
  }
}

export async function verifyOtp(req: Request, res: Response): Promise<void> {
  try {
    const { email, otp } = req.body;

    if (!email || !otp) {
      res.status(400).json({ error: 'Email and OTP are required' });
      return;
    }

    const normalized = email.trim().toLowerCase();

    const allowed = await prisma.allowedEmail.findUnique({ where: { email: normalized } });
    if (!allowed || !allowed.isActive) {
      res.status(403).json({ error: 'This email is not authorized to access the portal.' });
      return;
    }

    const otpToken = await prisma.otpToken.findFirst({
      where: {
        email: normalized,
        otp,
        used: false,
        expiresAt: { gt: new Date() },
      },
      orderBy: { createdAt: 'desc' },
    });

    if (!otpToken) {
      res.status(400).json({ error: 'Invalid or expired OTP' });
      return;
    }

    // Mark OTP as used
    await prisma.otpToken.update({
      where: { id: otpToken.id },
      data: { used: true },
    });

    // Find or create organizer
    let organizer = await prisma.organizer.findUnique({ where: { email: normalized } });
    let isNew = false;

    if (!organizer) {
      isNew = true;
      organizer = await prisma.organizer.create({
        data: { email: normalized },
      });

      // Create free plan for new organizer
      await prisma.plan.create({
        data: {
          organizerId: organizer.id,
          name: 'Free',
          totalCredits: 50,
          usedCredits: 0,
        },
      });
    }

    const token = jwt.sign(
      { organizerId: organizer.id },
      JWT_SECRET,
      { expiresIn: '30d' }
    );

    res.json({
      token,
      organizer,
      isNew,
    });
  } catch (error) {
    console.error('verifyOtp error:', error);
    res.status(500).json({ error: 'Failed to verify OTP' });
  }
}

export async function getMe(req: AuthRequest, res: Response): Promise<void> {
  try {
    const organizer = await prisma.organizer.findUnique({
      where: { id: req.organizerId },
      include: { plan: true },
    });
    if (!organizer) {
      res.status(404).json({ error: 'Organizer not found' });
      return;
    }
    res.json(organizer);
  } catch (error) {
    console.error('getMe error:', error);
    res.status(500).json({ error: 'Failed to load profile' });
  }
}

export async function updateMe(req: AuthRequest, res: Response): Promise<void> {
  try {
    const { name } = req.body;
    if (typeof name !== 'string') {
      res.status(400).json({ error: 'Name is required' });
      return;
    }
    const trimmed = name.trim();
    if (trimmed.length === 0 || trimmed.length > 100) {
      res.status(400).json({ error: 'Name must be 1–100 characters' });
      return;
    }
    const organizer = await prisma.organizer.update({
      where: { id: req.organizerId },
      data: { name: trimmed },
      include: { plan: true },
    });
    res.json(organizer);
  } catch (error) {
    console.error('updateMe error:', error);
    res.status(500).json({ error: 'Failed to update profile' });
  }
}
