'use strict';

// import required so Node type-strips this .cts (it has no other import).
import type { Db } from '../types/db';

const crypto = require('crypto');

function parseBrowser(userAgent: unknown): string {
  const ua = String(userAgent || '');
  if (/Edg\//i.test(ua)) return 'Edge';
  if (/OPR\//i.test(ua) || /Opera/i.test(ua)) return 'Opera';
  if (/Firefox\//i.test(ua)) return 'Firefox';
  if (/Chrome\//i.test(ua) || /CriOS\//i.test(ua)) return 'Chrome';
  if (/Safari\//i.test(ua)) return 'Safari';
  if (/curl\//i.test(ua)) return 'curl';
  if (/PostmanRuntime\//i.test(ua)) return 'Postman';
  return 'Unknown';
}

function parseOs(userAgent: unknown): string {
  const ua = String(userAgent || '');
  if (/iPhone|iPad|iPod/i.test(ua)) return 'iOS';
  if (/Android/i.test(ua)) return 'Android';
  if (/Windows NT/i.test(ua)) return 'Windows';
  if (/Mac OS X|Macintosh/i.test(ua)) return 'macOS';
  if (/Linux/i.test(ua)) return 'Linux';
  if (/CrOS/i.test(ua)) return 'ChromeOS';
  return 'Unknown';
}

function parseDeviceType(userAgent: unknown): string {
  const ua = String(userAgent || '');
  if (/iPad|Tablet/i.test(ua)) return 'tablet';
  if (/Mobi|iPhone|Android/i.test(ua)) return 'mobile';
  if (/curl|PostmanRuntime/i.test(ua)) return 'api';
  return 'desktop';
}

function coarseIpPrefix(ipAddress: unknown): string {
  const ip = String(ipAddress || '').trim();
  if (!ip) return '';

  const v4 = ip.match(/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.\d{1,3}$/);
  if (v4) return `${v4[1]}.${v4[2]}.${v4[3]}.0/24`;

  if (ip.includes(':')) {
    return `${ip.split(':').slice(0, 4).join(':')}::/64`;
  }

  return ip;
}

function buildDeviceFingerprint({
  userAgent,
  ipAddress,
}: {
  userAgent?: unknown;
  ipAddress?: unknown;
}) {
  const browser = parseBrowser(userAgent);
  const os = parseOs(userAgent);
  const deviceType = parseDeviceType(userAgent);
  const ipPrefix = coarseIpPrefix(ipAddress);
  const source = [browser, os, deviceType, String(userAgent || '').slice(0, 500), ipPrefix].join(
    '|',
  );
  const fingerprint = crypto.createHash('sha256').update(source).digest('hex').slice(0, 16);

  return {
    browser,
    os,
    device_type: deviceType,
    device_fingerprint: fingerprint,
  };
}

module.exports = {
  buildDeviceFingerprint,
  coarseIpPrefix,
  parseBrowser,
  parseDeviceType,
  parseOs,
};
