import { NextFunction, Request, Response } from 'express';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { RowDataPacket } from 'mysql2';
import { pool } from '../config/db.js';
import { AuthRequest } from '../middleware/auth.middleware.js';
import { getRolePermissions, unrestrictedPermissions } from '../services/permissionService.js';

interface UserRow extends RowDataPacket {
  id: number;
  name: string;
  email: string;
  password_hash: string;
  is_active: number;
}

interface MeRow extends RowDataPacket {
  id: number;
  name: string;
  email: string;
  role_id: number | null;
  role_name: string | null;
  is_active: number;
}

export async function login(req: Request, res: Response, next: NextFunction) {
  const { email, password } = req.body as { email?: string; password?: string };
  if (!email || !password) {
    return res.status(400).json({ message: 'Email and password are required' });
  }

  try {
    const [rows] = await pool.query<UserRow[]>(
      'SELECT id, name, email, password_hash, is_active FROM users WHERE email = ? LIMIT 1',
      [email],
    );
    const user = rows[0];
    if (!user || !user.is_active) {
      return res.status(401).json({ message: 'Invalid email or password' });
    }

    const valid = await bcrypt.compare(password, user.password_hash);
    if (!valid) {
      return res.status(401).json({ message: 'Invalid email or password' });
    }

    const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET!, { expiresIn: '7d' });
    const [meRows] = await pool.query<MeRow[]>(
      `SELECT u.id, u.name, u.email, u.role_id, r.name AS role_name, u.is_active
       FROM users u LEFT JOIN roles r ON r.id = u.role_id
       WHERE u.id = ? LIMIT 1`,
      [user.id],
    );
    const permissions = meRows[0]?.role_id
      ? await getRolePermissions(meRows[0].role_id)
      : unrestrictedPermissions();

    res.json({
      token,
      user: { id: user.id, name: user.name, email: user.email },
      permissions,
    });
  } catch (err) {
    next(err);
  }
}

export async function me(req: AuthRequest, res: Response, next: NextFunction) {
  try {
    const [rows] = await pool.query<MeRow[]>(
      `SELECT u.id, u.name, u.email, u.role_id, r.name AS role_name, u.is_active
       FROM users u LEFT JOIN roles r ON r.id = u.role_id
       WHERE u.id = ? LIMIT 1`,
      [req.userId],
    );
    const user = rows[0];
    if (!user || !user.is_active) {
      return res.status(401).json({ message: 'Unauthorized' });
    }

    const permissions = user.role_id ? await getRolePermissions(user.role_id) : unrestrictedPermissions();
    res.json({
      user: { id: user.id, name: user.name, email: user.email },
      permissions,
    });
  } catch (err) {
    next(err);
  }
}
