import { Router } from 'express';
import bcrypt from 'bcryptjs';
import { z } from 'zod';
import db from '../db/index.js';
import { signToken, requireAuth } from '../middleware/auth.js';
import { HttpError } from '../middleware/errorHandler.js';

const router = Router();

const RegisterSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
  displayName: z.string().min(1).optional(),
});

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

router.post('/register', (req, res, next) => {
  try {
    const body = RegisterSchema.parse(req.body);
    const exists = db.prepare('SELECT id FROM users WHERE email = ?').get(body.email);
    if (exists) throw new HttpError(409, 'Email already registered');

    // Le premier utilisateur inscrit devient automatiquement administrateur
    const isFirst = db.prepare('SELECT COUNT(*) AS n FROM users').get().n === 0;
    const role = isFirst ? 'admin' : 'user';

    const hash = bcrypt.hashSync(body.password, 10);
    const result = db
      .prepare('INSERT INTO users (email, password_hash, display_name, role) VALUES (?, ?, ?, ?)')
      .run(body.email, hash, body.displayName || null, role);

    const userId = result.lastInsertRowid;

    // Auto-create le premier profil famille (= l'utilisateur lui-même)
    const fullName = body.displayName || 'Mon profil';
    const prenom   = fullName.includes(' ') ? fullName.split(' ')[0] : null;
    const invResult = db.prepare(
      `INSERT INTO investisseurs (user_id, nom, prenom, type, type_fiscal, is_principal) VALUES (?, ?, ?, 'famille', 'PP', 1)`
    ).run(userId, fullName, prenom);

    // Auto-créer un compte courant pour le profil principal
    db.prepare(
      'INSERT INTO comptes (user_id, nom, type, investisseur_id) VALUES (?,?,?,?)'
    ).run(userId, `Compte courant — ${fullName}`, 'compte_courant', invResult.lastInsertRowid);

    const token = signToken({ sub: userId, email: body.email });
    res.status(201).json({
      token,
      user: { id: userId, email: body.email, displayName: body.displayName || null, role },
    });
  } catch (e) { next(e); }
});

router.post('/login', (req, res, next) => {
  try {
    const body = LoginSchema.parse(req.body);
    const user = db
      .prepare('SELECT id, email, password_hash, display_name, role FROM users WHERE email = ?')
      .get(body.email);
    if (!user) throw new HttpError(401, 'Invalid credentials');

    const ok = bcrypt.compareSync(body.password, user.password_hash);
    if (!ok) throw new HttpError(401, 'Invalid credentials');

    const token = signToken({ sub: user.id, email: user.email });
    res.json({
      token,
      user: { id: user.id, email: user.email, displayName: user.display_name, role: user.role },
    });
  } catch (e) { next(e); }
});

router.get('/me', requireAuth, (req, res) => {
  const user = db
    .prepare('SELECT id, email, display_name, role FROM users WHERE id = ?')
    .get(req.user.id);
  res.json({ user });
});

const UpdateMeSchema = z.object({
  displayName:     z.string().min(1).max(80).optional(),
  email:           z.string().email().optional(),
  currentPassword: z.string().optional(),
  newPassword:     z.string().min(8).optional(),
});

router.put('/me', requireAuth, (req, res, next) => {
  try {
    const body = UpdateMeSchema.parse(req.body);

    const current = db
      .prepare('SELECT id, email, password_hash, display_name FROM users WHERE id = ?')
      .get(req.user.id);

    let newHash = undefined;

    if (body.newPassword) {
      if (!body.currentPassword)
        throw new HttpError(400, 'Mot de passe actuel requis');
      const ok = bcrypt.compareSync(body.currentPassword, current.password_hash);
      if (!ok) throw new HttpError(401, 'Mot de passe actuel incorrect');
      newHash = bcrypt.hashSync(body.newPassword, 10);
    }

    if (body.email && body.email !== current.email) {
      const taken = db.prepare('SELECT id FROM users WHERE email = ? AND id != ?').get(body.email, req.user.id);
      if (taken) throw new HttpError(409, 'Email déjà utilisé par un autre compte');
    }

    const newEmail        = body.email       ?? current.email;
    const newDisplayName  = body.displayName !== undefined ? body.displayName : current.display_name;
    const newPasswordHash = newHash ?? current.password_hash;

    db.prepare(
      "UPDATE users SET email=?, display_name=?, password_hash=?, updated_at=datetime('now') WHERE id=?"
    ).run(newEmail, newDisplayName, newPasswordHash, req.user.id);

    const token = newEmail !== current.email
      ? signToken({ sub: req.user.id, email: newEmail })
      : undefined;

    res.json({
      user: { id: req.user.id, email: newEmail, display_name: newDisplayName },
      ...(token ? { token } : {}),
    });
  } catch (e) { next(e); }
});

export default router;
