// programs/log.js
'use strict';

const fs = require('fs');
const path = require('path');

// --- configuration ---
const LOG_DIR = path.join(__dirname, '..', 'logs');
fs.mkdirSync(LOG_DIR, { recursive: true });

function getLogFilePath(d = new Date()) {
  const yyyy = d.getFullYear();
  const mm = String(d.getMonth() + 1).padStart(2, '0');
  const dd = String(d.getDate()).padStart(2, '0');
  return path.join(LOG_DIR, `${yyyy}_${mm}_${dd}.txt`);
}

function write(obj) {
  const line = JSON.stringify(obj) + '\n';
  fs.appendFile(getLogFilePath(), line, (err) => {
    if (err) console.error('[log] write error:', err);
  });
}

// --- common extractors ---
function commonFromReq(req) {
  try {
    const xff = req?.headers?.['x-forwarded-for'];
    const xRealIp = req?.headers?.['x-real-ip'];
    const ipFromXff = xff ? xff.split(',')[0].trim() : null;
    const ip =
      ipFromXff ||
      xRealIp ||
      req?.ip ||
      req?.socket?.remoteAddress ||
      null;

    const tls =
      req?.socket?.encrypted
        ? {
            protocol:
              typeof req.socket.getProtocol === 'function'
                ? req.socket.getProtocol()
                : null,
            cipher:
              typeof req.socket.getCipher === 'function'
                ? (req.socket.getCipher() || {}).name
                : null,
          }
        : null;

    // MAC is not available across routed networks
    const mac = null;

    return {
      ip,
      ips: Array.isArray(req?.ips) ? req.ips : [],
      xff: xff || null,
      remoteAddress: req?.socket?.remoteAddress || null,
      remoteFamily: req?.socket?.remoteFamily || null,
      userAgent: req?.headers?.['user-agent'] || null,
      acceptLanguage: req?.headers?.['accept-language'] || null,
      secChUa: req?.headers?.['sec-ch-ua'] || null,
      secChUaPlatform: req?.headers?.['sec-ch-ua-platform'] || null,
      secChUaMobile: req?.headers?.['sec-ch-ua-mobile'] || null,
      referer: req?.headers?.['referer'] || null,
      tls,
      mac,
    };
  } catch {
    return {};
  }
}

function commonFromSocket(socket) {
  return {
    remoteAddress: socket?.remoteAddress || null,
    remoteFamily: socket?.remoteFamily || null,
  };
}

// --- specific log functions ---
function logHttpRequest(req) {
  write({
    ts: new Date().toISOString(),
    type: 'http',
    method: req?.method || null,
    url: (req?.originalUrl ?? req?.url) || null,
    ...commonFromReq(req),
  });
}

function logTcpConnection(socket) {
  write({
    ts: new Date().toISOString(),
    type: 'tcp',
    ...commonFromSocket(socket),
  });
}

function logHttpUpgrade(req) {
  write({
    ts: new Date().toISOString(),
    type: 'http-upgrade',
    url: req?.url || null,
    ...commonFromReq(req),
  });
}

function logWssConnected(req) {
  write({
    ts: new Date().toISOString(),
    type: 'wss',
    url: req?.url || null,
    ...commonFromReq(req),
  });
}

function logWssClosed(req, code, reason) {
  write({
    ts: new Date().toISOString(),
    type: 'wss-close',
    url: req?.url || null,
    code: typeof code === 'number' ? code : null,
    reason: reason ? reason.toString() : null,
    ...commonFromReq(req),
  });
}

function logSnapshot(python, response){
  write({
    ts: new Date().toISOString(),
    type: 'snapshot',
    command: python.toString(),
    wsResponse: response.toString()
  })
}

// --- generic hooks you requested ---
function connected(context = {}) {
  write({
    ts: new Date().toISOString(),
    type: 'connected',
    ...context,
  });
}

function connectionLost(context = {}) {
  write({
    ts: new Date().toISOString(),
    type: 'connection-lost',
    ...context,
  });
}

module.exports = {
  logHttpRequest,
  logTcpConnection,
  logHttpUpgrade,
  logWssConnected,
  logSnapshot,
  logWssClosed,
  connected,
  connectionLost,
};
