const crypto = require('crypto');

const COOKIE_NAME = 'plai_wallet_user';
const SESSION_VERSION = 2;
const SESSION_TTL_MS = 30 * 60 * 1000;
const SESSION_COOKIE_OPTIONS = {
  httpOnly: true,
  sameSite: 'lax',
  secure: process.env.NODE_ENV === 'production'
};

function getSecret() {
  return process.env.AISFOR_CHAIN_WALLET_SSO_SECRET ||
    process.env.AISFOR_CHAIN_KEY_AISFOR ||
    process.env.AISFOR_CHAIN_ADMIN_SESSION_SECRET ||
    '';
}

function base64Url(input) {
  return Buffer.from(input)
    .toString('base64')
    .replace(/=/g, '')
    .replace(/\+/g, '-')
    .replace(/\//g, '_');
}

function fromBase64Url(input) {
  const value = String(input || '').replace(/-/g, '+').replace(/_/g, '/');
  const padded = value + '='.repeat((4 - (value.length % 4)) % 4);
  return Buffer.from(padded, 'base64').toString('utf8');
}

function signBody(body) {
  const secret = getSecret();
  if (!secret) {
    const err = new Error('Wallet SSO secret is not configured.');
    err.status = 500;
    err.code = 'WALLET_SSO_SECRET_MISSING';
    throw err;
  }

  return crypto.createHmac('sha256', secret).update(body).digest('base64url');
}

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

function encodeWalletToken(payload = {}, ttlMs = 5 * 60 * 1000) {
  const now = Date.now();
  const userId = String(payload.userId || '').trim();
  if (!userId) {
    const err = new Error('Wallet user id is required.');
    err.status = 400;
    err.code = 'WALLET_USER_REQUIRED';
    throw err;
  }

  const body = base64Url(JSON.stringify({
    aud: 'plai-wallet',
    ver: SESSION_VERSION,
    userId,
    userid: String(payload.userid || payload.username || payload.loginId || '').slice(0, 80),
    username: String(payload.username || payload.userid || payload.loginId || '').slice(0, 80),
    loginId: String(payload.loginId || payload.userid || payload.username || '').slice(0, 80),
    mongoId: String(payload.mongoId || payload._id || payload.id || '').slice(0, 80),
    displayName: String(payload.displayName || payload.userid || userId).slice(0, 80),
    iat: now,
    exp: now + ttlMs
  }));
  return `${body}.${signBody(body)}`;
}

function verifyWalletToken(token) {
  const [body, signature] = String(token || '').split('.');
  if (!body || !signature || !safeEqual(signature, signBody(body))) {
    const err = new Error('Invalid wallet login token.');
    err.status = 401;
    err.code = 'INVALID_WALLET_TOKEN';
    throw err;
  }

  let payload;
  try {
    payload = JSON.parse(fromBase64Url(body));
  } catch (error) {
    const err = new Error('Invalid wallet login token payload.');
    err.status = 401;
    err.code = 'INVALID_WALLET_TOKEN';
    throw err;
  }

  if (
    payload.aud !== 'plai-wallet' ||
    Number(payload.ver || 0) !== SESSION_VERSION ||
    !payload.userId ||
    Number(payload.exp || 0) < Date.now()
  ) {
    const err = new Error('Wallet login token expired.');
    err.status = 401;
    err.code = 'WALLET_TOKEN_EXPIRED';
    throw err;
  }

  return {
    userId: String(payload.userId),
    userid: String(payload.userid || '').slice(0, 80),
    username: String(payload.username || '').slice(0, 80),
    loginId: String(payload.loginId || '').slice(0, 80),
    mongoId: String(payload.mongoId || '').slice(0, 80),
    displayName: String(payload.displayName || payload.userid || payload.username || payload.userId).slice(0, 80)
  };
}

function parseCookies(req) {
  return String(req.headers.cookie || '')
    .split(';')
    .map(part => part.trim())
    .filter(Boolean)
    .reduce((cookies, part) => {
      const index = part.indexOf('=');
      if (index === -1) return cookies;
      cookies[part.slice(0, index)] = decodeURIComponent(part.slice(index + 1));
      return cookies;
    }, {});
}

function getWalletSession(req) {
  const token = parseCookies(req)[COOKIE_NAME];
  if (!token) return null;
  try {
    return verifyWalletToken(token);
  } catch (error) {
    return null;
  }
}

function setWalletSession(res, user) {
  const token = encodeWalletToken(user, SESSION_TTL_MS);
  res.cookie(COOKIE_NAME, token, {
    ...SESSION_COOKIE_OPTIONS,
    path: '/',
    maxAge: SESSION_TTL_MS
  });
}

function clearWalletSession(res) {
  res.clearCookie(COOKIE_NAME, {
    ...SESSION_COOKIE_OPTIONS,
    path: '/'
  });
  res.clearCookie(COOKIE_NAME, {
    ...SESSION_COOKIE_OPTIONS,
    path: '/wallet'
  });
}

function attachWalletUser(req, res, next) {
  req.walletUser = getWalletSession(req);
  next();
}

function requireWalletUser(req, res, next) {
  if (req.walletUser && req.walletUser.userId) return next();
  return res.redirect('/wallet/login-required');
}

module.exports = {
  attachWalletUser,
  clearWalletSession,
  encodeWalletToken,
  requireWalletUser,
  setWalletSession,
  verifyWalletToken
};
