// backend/src/routes/auth.js
import { Router } from 'express';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { z } from 'zod';
import { query, transaction } from '../utils/db.js';
import { generateToken } from '../utils/encryption.js';
import { sendEmail } from '../services/email.js';
import { requireAuth } from '../middleware/auth.js';

const router = Router();

const RegisterSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
  fullName: z.string().min(2).max(100),
  planId: z.enum(['starter', 'pro', 'agency']).default('starter'),
  locale: z.enum(['en', 'ro']).default('en'),
});

const LoginSchema = z.object({
  email: z.string().email(),
  password: z.string(),
});

// POST /api/auth/register
router.post('/register', async (req, res) => {
  try {
    const data = RegisterSchema.parse(req.body);

    const existing = await query('SELECT id FROM users WHERE email = $1', [data.email]);
    if (existing.rows[0]) {
      return res.status(409).json({ error: 'email_taken', message: 'Email already registered' });
    }

    const passwordHash = await bcrypt.hash(data.password, 12);
    const verifyToken = generateToken();
    const trialEnds = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000);

    const result = await transaction(async (client) => {
      const { rows } = await client.query(
        `INSERT INTO users (email, password_hash, full_name, plan_id, status, trial_ends_at, locale, email_verify_token)
         VALUES ($1, $2, $3, $4, 'trial', $5, $6, $7) RETURNING id, email, full_name, role, plan_id, status, locale`,
        [data.email, passwordHash, data.fullName, data.planId, trialEnds, data.locale, verifyToken]
      );
      const user = rows[0];

      // Create empty profile
      await client.query('INSERT INTO user_profiles (user_id) VALUES ($1)', [user.id]);

      // Create Stripe customer (async, non-blocking)
      createStripeCustomer(user.id, data.email, data.fullName).catch(console.error);

      return user;
    });

    // Send verification email
    await sendEmail({
      to: data.email,
      subject: 'Verify your Content Machine account',
      template: 'verify-email',
      data: { name: data.fullName, token: verifyToken, locale: data.locale }
    });

    const token = jwt.sign({ userId: result.id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES_IN });

    res.status(201).json({
      token,
      user: { id: result.id, email: result.email, fullName: result.full_name, role: result.role, planId: result.plan_id, status: result.status, locale: result.locale }
    });
  } catch (err) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'validation', issues: err.issues });
    res.status(500).json({ error: 'server_error' });
  }
});

// POST /api/auth/login
router.post('/login', async (req, res) => {
  try {
    const data = LoginSchema.parse(req.body);
    const { rows } = await query(
      `SELECT u.*, p.scripts_per_day as plan_scripts, p.byok, p.white_label
       FROM users u LEFT JOIN plans p ON u.plan_id = p.id WHERE u.email = $1`,
      [data.email]
    );
    const user = rows[0];

    if (!user || !(await bcrypt.compare(data.password, user.password_hash))) {
      return res.status(401).json({ error: 'invalid_credentials', message: 'Invalid email or password' });
    }
    if (user.status === 'banned') return res.status(403).json({ error: 'account_banned' });

    // Check trial expiry
    if (user.status === 'trial' && user.trial_ends_at < new Date()) {
      await query("UPDATE users SET status = 'past_due' WHERE id = $1", [user.id]);
      user.status = 'past_due';
    }

    const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES_IN });

    res.json({
      token,
      user: {
        id: user.id, email: user.email, fullName: user.full_name,
        role: user.role, planId: user.plan_id, status: user.status,
        locale: user.locale, trialEndsAt: user.trial_ends_at,
        emailVerified: user.email_verified, byok: user.byok,
        onboardingCompleted: user.onboarding_completed || false
      }
    });
  } catch (err) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'validation', issues: err.issues });
    res.status(500).json({ error: 'server_error' });
  }
});

// GET /api/auth/me
router.get('/me', requireAuth, async (req, res) => {
  const { rows } = await query(
    `SELECT u.id, u.email, u.full_name, u.role, u.plan_id, u.status, u.locale,
            u.trial_ends_at, u.email_verified, u.current_period_end,
            p.name as plan_name, p.scripts_per_day, p.posts_per_day, p.byok, p.white_label, p.max_sub_clients
     FROM users u LEFT JOIN plans p ON u.plan_id = p.id WHERE u.id = $1`,
    [req.user.id]
  );
  const u = rows[0];
  res.json({
    id: u.id, email: u.email, fullName: u.full_name, role: u.role,
    planId: u.plan_id, planName: u.plan_name, status: u.status,
    locale: u.locale, trialEndsAt: u.trial_ends_at, emailVerified: u.email_verified,
    currentPeriodEnd: u.current_period_end, onboardingCompleted: u.onboarding_completed || false,
    plan: { scriptsPerDay: u.scripts_per_day, postsPerDay: u.posts_per_day, byok: u.byok, whiteLabel: u.white_label, maxSubClients: u.max_sub_clients }
  });
});

// POST /api/auth/verify-email
router.post('/verify-email', async (req, res) => {
  const { token } = req.body;
  if (!token) return res.status(400).json({ error: 'Token required' });
  const { rows } = await query(
    "UPDATE users SET email_verified = true, email_verify_token = NULL WHERE email_verify_token = $1 RETURNING id",
    [token]
  );
  if (!rows[0]) return res.status(400).json({ error: 'Invalid or expired token' });
  res.json({ success: true });
});

// POST /api/auth/forgot-password
router.post('/forgot-password', async (req, res) => {
  const { email } = req.body;
  const { rows } = await query('SELECT id, full_name, locale FROM users WHERE email = $1', [email]);
  if (rows[0]) {
    const token = generateToken();
    const expires = new Date(Date.now() + 60 * 60 * 1000); // 1 hour
    await query('UPDATE users SET reset_token = $1, reset_token_expires = $2 WHERE id = $3', [token, expires, rows[0].id]);
    await sendEmail({
      to: email,
      subject: 'Reset your password',
      template: 'reset-password',
      data: { name: rows[0].full_name, token, locale: rows[0].locale }
    });
  }
  // Always return success (don't reveal if email exists)
  res.json({ success: true });
});

// POST /api/auth/reset-password
router.post('/reset-password', async (req, res) => {
  const { token, password } = req.body;
  if (!token || !password || password.length < 8) return res.status(400).json({ error: 'Invalid request' });
  const { rows } = await query(
    "SELECT id FROM users WHERE reset_token = $1 AND reset_token_expires > NOW()",
    [token]
  );
  if (!rows[0]) return res.status(400).json({ error: 'Invalid or expired token' });
  const hash = await bcrypt.hash(password, 12);
  await query("UPDATE users SET password_hash = $1, reset_token = NULL, reset_token_expires = NULL WHERE id = $2", [hash, rows[0].id]);
  res.json({ success: true });
});

// PATCH /api/auth/locale
router.patch('/locale', requireAuth, async (req, res) => {
  const { locale } = req.body;
  if (!['en', 'ro'].includes(locale)) return res.status(400).json({ error: 'Invalid locale' });
  await query('UPDATE users SET locale = $1 WHERE id = $2', [locale, req.user.id]);
  res.json({ success: true, locale });
});

async function createStripeCustomer(userId, email, name) {
  const { default: Stripe } = await import('stripe');
  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
  const customer = await stripe.customers.create({ email, name, metadata: { userId } });
  await query('UPDATE users SET stripe_customer_id = $1 WHERE id = $2', [customer.id, userId]);
}

export default router;

// POST /api/auth/complete-onboarding
router.post('/complete-onboarding', requireAuth, async (req, res) => {
  await query(
    'UPDATE users SET onboarding_completed = true, onboarding_completed_at = NOW() WHERE id = $1',
    [req.user.id]
  );
  res.json({ success: true });
});
