const crypto = require('crypto');

const COOKIE_NAME = 'plai_admin_session';
const SESSION_TTL_MS = 12 * 60 * 60 * 1000;

function safeEqual(a, b) {
  const left = Buffer.from(String(a || ''), 'utf8');
  const right = Buffer.from(String(b || ''), 'utf8');
  if (left.length !== right.length) return false;
  return crypto.timingSafeEqual(left, right);
}

function getAdminCredentials() {
  return {
    username: process.env.AISFOR_CHAIN_ADMIN_USER || 'ellia',
    password: process.env.AISFOR_CHAIN_ADMIN_PASSWORD || process.env.AISFOR_CHAIN_KEY_AISFOR || ''
  };
}

function getSessionSecret() {
  return [
    process.env.AISFOR_CHAIN_ADMIN_SESSION_SECRET,
    process.env.AISFOR_CHAIN_ADMIN_PASSWORD,
    process.env.AISFOR_CHAIN_KEY_AISFOR
  ].filter(Boolean).join(':');
}

function authenticateAdmin(username, password) {
  const credentials = getAdminCredentials();
  return Boolean(
    credentials.password
      && safeEqual(username, credentials.username)
      && safeEqual(password, credentials.password)
  );
}

function parseCookies(header = '') {
  return String(header || '').split(';').reduce((cookies, part) => {
    const splitAt = part.indexOf('=');
    if (splitAt < 0) return cookies;
    const key = part.slice(0, splitAt).trim();
    const value = part.slice(splitAt + 1).trim();
    if (key) cookies[key] = decodeURIComponent(value);
    return cookies;
  }, {});
}

function signSession(username, expiresAt) {
  const secret = getSessionSecret();
  if (!secret) return '';
  return crypto
    .createHmac('sha256', secret)
    .update(`${username}.${expiresAt}`)
    .digest('hex');
}

function createSessionToken(username) {
  const expiresAt = Date.now() + SESSION_TTL_MS;
  const signature = signSession(username, expiresAt);
  return Buffer.from(`${username}.${expiresAt}.${signature}`, 'utf8').toString('base64url');
}

function verifySessionToken(token) {
  try {
    const decoded = Buffer.from(String(token || ''), 'base64url').toString('utf8');
    const [username, expiresAtText, signature] = decoded.split('.');
    const expiresAt = Number(expiresAtText);
    if (!username || !Number.isFinite(expiresAt) || !signature) return false;
    if (Date.now() > expiresAt) return false;
    return safeEqual(signature, signSession(username, expiresAt));
  } catch (error) {
    return false;
  }
}

function sessionCookie(token) {
  const secure = process.env.NODE_ENV === 'production' || process.env.AISFOR_CHAIN_COOKIE_SECURE === '1';
  return [
    `${COOKIE_NAME}=${encodeURIComponent(token)}`,
    'Path=/admin',
    'HttpOnly',
    'SameSite=Lax',
    `Max-Age=${Math.floor(SESSION_TTL_MS / 1000)}`,
    secure ? 'Secure' : ''
  ].filter(Boolean).join('; ');
}

function clearSessionCookie() {
  return `${COOKIE_NAME}=; Path=/admin; HttpOnly; SameSite=Lax; Max-Age=0`;
}

function setAdminSession(res, username) {
  res.setHeader('Set-Cookie', sessionCookie(createSessionToken(username)));
}

function clearAdminSession(res) {
  res.setHeader('Set-Cookie', clearSessionCookie());
}

function requireAdminAuth(req, res, next) {
  const credentials = getAdminCredentials();
  if (!credentials.password) {
    return res.status(503).json({
      ok: false,
      error: 'ADMIN_AUTH_NOT_CONFIGURED',
      message: 'AISFOR_CHAIN_ADMIN_PASSWORD is required for admin access.'
    });
  }

  const cookies = parseCookies(req.get('cookie'));
  if (verifySessionToken(cookies[COOKIE_NAME])) return next();

  return res.redirect(`/admin/login?next=${encodeURIComponent(req.originalUrl || '/admin')}`);
}

module.exports = {
  authenticateAdmin,
  clearAdminSession,
  requireAdminAuth,
  setAdminSession
};
