import { Router } from 'express';
import bcrypt from 'bcrypt';
import { prisma } from '../db.js';
import { publicUser, requireAuth } from '../middleware.js';
import { unlockAchievement } from '../achievements.js';

const router = Router();
const STARTING_BALANCE = Number(process.env.STARTING_BALANCE || 10000);
const STARTING_OSU = Number(process.env.STARTING_OSU || 100);

router.post('/register', async (req, res) => {
  try {
    const username = String(req.body.username || '').trim();
    const password = String(req.body.password || '');

    if (username.length < 3 || username.length > 32) {
      return res.status(400).json({ error: 'Username must be 3–32 characters' });
    }
    if (!/^[a-zA-Z0-9_]+$/.test(username)) {
      return res.status(400).json({ error: 'Username may only contain letters, numbers, and underscores' });
    }
    if (password.length < 6) {
      return res.status(400).json({ error: 'Password must be at least 6 characters' });
    }

    const existing = await prisma.user.findUnique({ where: { username } });
    if (existing) {
      return res.status(409).json({ error: 'Username already taken' });
    }

    const passwordHash = await bcrypt.hash(password, 10);
    const user = await prisma.user.create({
      data: {
        username,
        passwordHash,
        balance: String(STARTING_BALANCE),
        osuBalance: STARTING_OSU,
        role: 'user',
      },
    });

    await prisma.transaction.create({
      data: {
        userId: user.id,
        type: 'seed_credit',
        amount: String(STARTING_BALANCE),
        meta: JSON.stringify({ reason: 'starting_balance' }),
      },
    });

    await prisma.transaction.create({
      data: {
        userId: user.id,
        type: 'seed_osu',
        amount: String(STARTING_OSU),
        meta: JSON.stringify({ reason: 'starting_osu' }),
      },
    });

    req.session.userId = user.id;
    req.session.role = user.role;

    const withConn = await prisma.user.update({
      where: { id: user.id },
      data: { lastConnection: new Date() },
    });
    await unlockAchievement(user.id, 'welcome');

    res.status(201).json({ user: publicUser(withConn) });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Registration failed' });
  }
});

router.post('/login', async (req, res) => {
  try {
    const username = String(req.body.username || '').trim();
    const password = String(req.body.password || '');

    const user = await prisma.user.findUnique({ where: { username } });
    if (!user) {
      return res.status(401).json({ error: 'Invalid username or password' });
    }

    const ok = await bcrypt.compare(password, user.passwordHash);
    if (!ok) {
      return res.status(401).json({ error: 'Invalid username or password' });
    }

    req.session.userId = user.id;
    req.session.role = user.role;

    const withConn = await prisma.user.update({
      where: { id: user.id },
      data: { lastConnection: new Date() },
    });

    // Offline vault yield if user is not already socket-connected
    let vaultCredited = '0';
    try {
      const { isConnected } = await import('../presence.js');
      const { settleVaultYield } = await import('../vault.js');
      if (!isConnected(user.id)) {
        const settled = await settleVaultYield(user.id, 'offline');
        vaultCredited = settled.credited || '0';
      }
    } catch (err) {
      console.error('login vault settle', err);
    }

    const refreshed =
      vaultCredited !== '0' && vaultCredited !== 0
        ? await prisma.user.findUnique({ where: { id: user.id } })
        : withConn;

    res.json({ user: publicUser(refreshed), vaultCredited });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Login failed' });
  }
});

router.post('/logout', (req, res) => {
  req.session.destroy((err) => {
    if (err) {
      return res.status(500).json({ error: 'Logout failed' });
    }
    res.clearCookie('connect.sid');
    res.json({ ok: true });
  });
});

router.get('/me', requireAuth, async (req, res) => {
  try {
    const user = await prisma.user.findUnique({ where: { id: req.session.userId } });
    if (!user) {
      return res.status(401).json({ error: 'User not found' });
    }
    res.json({ user: publicUser(user) });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to load user' });
  }
});

export default router;
