import type { GeoDeviceContext, GeoLocation, ClientContext } from '../types.js';
import { lookupByIP } from './geo.js';
import { parseUserAgent } from './device.js';

const getClientIP = (req: { headers: Record<string, string | string[] | undefined> }): string => {
  const forwarded = req.headers['x-forwarded-for'];
  if (typeof forwarded === 'string') {
    return forwarded.split(',')[0].trim();
  }
  if (Array.isArray(forwarded)) {
    return (forwarded[0] ?? '').split(',')[0].trim();
  }
  return (req.headers['x-real-ip'] as string) ?? '';
};

export const buildContext = (
  req: { headers: Record<string, string | string[] | undefined>; socket?: { remoteAddress?: string } },
  clientData?: Partial<{
    geo: Partial<GeoLocation>;
    client: Partial<ClientContext>;
  }>,
): GeoDeviceContext => {
  const ip = getClientIP(req) || req.socket?.remoteAddress?.replace(/^::ffff:/, '') || '';
  const userAgent = (req.headers['user-agent'] as string) ?? '';
  const acceptLanguage = (req.headers['accept-language'] as string) ?? undefined;

  const { device, browser, os } = parseUserAgent(userAgent);

  let geo: GeoLocation | null = clientData?.geo
    ? {
        latitude: clientData.geo.latitude ?? 0,
        longitude: clientData.geo.longitude ?? 0,
        country: clientData.geo.country ?? '',
        countryCode: clientData.geo.countryCode ?? '',
        region: clientData.geo.region ?? '',
        city: clientData.geo.city ?? '',
        timezone: clientData.geo.timezone ?? '',
        source: 'client',
      }
    : lookupByIP(ip);

  const client: ClientContext = {
    screenWidth: clientData?.client?.screenWidth,
    screenHeight: clientData?.client?.screenHeight,
    viewportWidth: clientData?.client?.viewportWidth,
    viewportHeight: clientData?.client?.viewportHeight,
    devicePixelRatio: clientData?.client?.devicePixelRatio,
    timezone: clientData?.client?.timezone,
    language: clientData?.client?.language,
    languages: clientData?.client?.languages,
    platform: clientData?.client?.platform,
    hardwareConcurrency: clientData?.client?.hardwareConcurrency,
    deviceMemory: clientData?.client?.deviceMemory,
    cookieEnabled: clientData?.client?.cookieEnabled,
    doNotTrack: clientData?.client?.doNotTrack,
  };

  return {
    geo,
    device,
    browser,
    os,
    client,
    ip: ip || undefined,
    userAgent,
    acceptLanguage,
    requestedAt: new Date().toISOString(),
  };
};
