import { Request, Response, NextFunction } from 'express';
import * as jwt from 'jsonwebtoken';
import { queryOne } from '../db/pool';
import { logger } from '../lib/logger';

export interface AuthenticatedRequest extends Request {
  user?: {
    id: string;
    username: string;
    email: string;
    status: string;
  };
}

export interface JwtPayload {
  sub: string;       // user id
  username: string;
  email: string;
  status: string;
  iat: number;
  exp: number;
}

const JWT_SECRET = process.env.JWT_SECRET as jwt.Secret;
const REFRESH_SECRET = process.env.REFRESH_TOKEN_SECRET as jwt.Secret;

const ACCESS_EXPIRES = (process.env.JWT_EXPIRES_IN ?? '15m') as jwt.SignOptions['expiresIn'];
const REFRESH_EXPIRES = (process.env.REFRESH_TOKEN_EXPIRES_IN ?? '30d') as jwt.SignOptions['expiresIn'];

// ─── Token generation ─────────────────────────────────────────────────────────

export function generateAccessToken(payload: Omit<JwtPayload, 'iat' | 'exp'>): string {
  return jwt.sign(payload, JWT_SECRET, { expiresIn: ACCESS_EXPIRES });
}

export function generateRefreshToken(userId: string): string {
  return jwt.sign({ sub: userId }, REFRESH_SECRET, { expiresIn: REFRESH_EXPIRES });
}

export function verifyAccessToken(token: string): JwtPayload {
  return jwt.verify(token, JWT_SECRET) as JwtPayload;
}

export function verifyRefreshToken(token: string): { sub: string } {
  return jwt.verify(token, REFRESH_SECRET) as { sub: string };
}

// ─── Auth middleware ──────────────────────────────────────────────────────────

export function authenticate(
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    res.status(401).json({ error: 'UNAUTHORIZED', message: 'Missing or invalid authorization header' });
    return;
  }

  const token = authHeader.slice(7);

  try {
    const payload = verifyAccessToken(token);

    if (payload.status === 'banned') {
      res.status(403).json({ error: 'BANNED', message: 'This account has been banned.' });
      return;
    }

    req.user = {
      id: payload.sub,
      username: payload.username,
      email: payload.email,
      status: payload.status,
    };

    next();
  } catch (err) {
    if (err instanceof jwt.TokenExpiredError) {
      res.status(401).json({ error: 'TOKEN_EXPIRED', message: 'Access token expired' });
    } else {
      res.status(401).json({ error: 'INVALID_TOKEN', message: 'Invalid access token' });
    }
  }
}

export function optionalAuthenticate(
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    return next();
  }
  return authenticate(req, res, next);
}

// ─── Admin middleware ─────────────────────────────────────────────────────────

const ADMIN_USER_IDS = (process.env.ADMIN_USER_IDS || '').split(',').filter(Boolean);

export function requireAdmin(
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void {
  if (!req.user) {
    res.status(401).json({ error: 'UNAUTHORIZED', message: 'Authentication required' });
    return;
  }
  if (!ADMIN_USER_IDS.includes(req.user.id)) {
    res.status(403).json({ error: 'FORBIDDEN', message: 'Admin access required' });
    return;
  }
  next();
}
