'use strict';

const jwt    = require('jsonwebtoken');
const crypto = require('crypto');
const { queryOne, query } = require('../config/db');

// ── JWT Auth ────────────────────────────────────────────────────
async function requireAuth(req, res, next) {
  try {
    const header = req.headers.authorization || '';
    if (!header.startsWith('Bearer ')) {
      return res.status(401).json({ error: 'Missing or invalid Authorization header.' });
    }

    const token = header.slice(7);

    // Determine if it's a JWT or an API key
    if (token.startsWith('cp_live_') || token.startsWith('cp_test_')) {
      return apiKeyAuth(req, res, next, token);
    }

    // JWT
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    const user = await queryOne(
      'SELECT id, uuid, name, email, role, plan, status, avatar FROM users WHERE id = ? AND status = "active"',
      [payload.sub]
    );

    if (!user) {
      return res.status(401).json({ error: 'User not found or account suspended.' });
    }

    req.user = user;
    req.authType = 'jwt';
    next();
  } catch (err) {
    if (err.name === 'TokenExpiredError') {
      return res.status(401).json({ error: 'Token expired.', code: 'TOKEN_EXPIRED' });
    }
    return res.status(401).json({ error: 'Invalid token.' });
  }
}

// ── API Key Auth ─────────────────────────────────────────────────
async function apiKeyAuth(req, res, next, rawKey) {
  const keyHash = hashApiKey(rawKey);

  const apiKey = await queryOne(
    `SELECT ak.*, u.id as user_id_real, u.uuid, u.name, u.email, u.role, u.plan, u.status, u.avatar
     FROM api_keys ak
     JOIN users u ON u.id = ak.user_id
     WHERE ak.key_hash = ? AND ak.status = "active" AND u.status = "active"`,
    [keyHash]
  );

  if (!apiKey) {
    return res.status(401).json({ error: 'Invalid or revoked API key.' });
  }

  // Update last used (fire and forget)
  query(
    'UPDATE api_keys SET last_used_at = NOW(), last_used_ip = ?, requests_count = requests_count + 1 WHERE id = ?',
    [req.ip, apiKey.id]
  ).catch(() => {});

  req.user = {
    id:     apiKey.user_id,
    uuid:   apiKey.uuid,
    name:   apiKey.name,
    email:  apiKey.email,
    role:   apiKey.role,
    plan:   apiKey.plan,
    status: apiKey.status,
    avatar: apiKey.avatar,
  };
  req.apiKey   = apiKey;
  req.authType = 'apikey';
  req.environment = apiKey.environment;
  next();
}

// ── Admin Only ────────────────────────────────────────────────────
function requireAdmin(req, res, next) {
  if (!req.user || (req.user.role !== 'admin' && req.user.role !== 'superadmin')) {
    return res.status(403).json({ error: 'Admin access required.' });
  }
  next();
}

function requireSuperAdmin(req, res, next) {
  if (!req.user || req.user.role !== 'superadmin') {
    return res.status(403).json({ error: 'Superadmin access required.' });
  }
  next();
}

// ── Pro Plan Only ─────────────────────────────────────────────────
function requirePro(req, res, next) {
  if (!req.user) return res.status(401).json({ error: 'Unauthorized.' });
  if (req.user.plan === 'free') {
    return res.status(402).json({
      error:   'Pro license required.',
      code:    'UPGRADE_REQUIRED',
      upgrade: 'https://chainpay.store/pricing',
    });
  }
  next();
}

// ── Helpers ───────────────────────────────────────────────────────
function hashApiKey(rawKey) {
  return crypto.createHash('sha256').update(rawKey).digest('hex');
}

function generateApiKey(env = 'live') {
  const prefix = `cp_${env}_`;
  const secret = crypto.randomBytes(24).toString('hex');
  const raw    = prefix + secret;
  const hash   = hashApiKey(raw);
  const preview = raw.slice(0, 12) + '…' + raw.slice(-4);
  return { raw, hash, preview, prefix: prefix.slice(0, -1) };
}

function signJwt(userId, extra = {}) {
  return jwt.sign(
    { sub: userId, ...extra },
    process.env.JWT_SECRET,
    { expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
  );
}

function signRefreshToken(userId) {
  return jwt.sign(
    { sub: userId, type: 'refresh' },
    process.env.JWT_REFRESH_SECRET || process.env.JWT_SECRET,
    { expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '30d' }
  );
}

module.exports = {
  requireAuth,
  requireAdmin,
  requireSuperAdmin,
  requirePro,
  hashApiKey,
  generateApiKey,
  signJwt,
  signRefreshToken,
};
