/**
 * Клиент для Geo Device Service.
 * Собирает данные с клиента и отправляет на сервис для полного контекста.
 */

const GEO_CONTEXT_API = '/api/geo-context';

export interface GeoDeviceContext {
  geo: {
    latitude: number;
    longitude: number;
    country: string;
    countryCode: string;
    region: string;
    city: string;
    timezone: string;
    source: string;
  } | null;
  device: {
    type: 'desktop' | 'mobile' | 'tablet' | 'wearable' | 'smarttv' | 'unknown';
    vendor?: string;
    model?: string;
  };
  browser: { name: string; version: string; full: string };
  os: { name: string; version: string; full: string };
  client: Record<string, unknown>;
  ip?: string;
  userAgent: string;
  acceptLanguage?: string;
  requestedAt: string;
}

const collectClientData = (): {
  geo?: { latitude: number; longitude: number; city?: string; country?: string; timezone?: string };
  client?: {
    screenWidth?: number;
    screenHeight?: number;
    viewportWidth?: number;
    viewportHeight?: number;
    devicePixelRatio?: number;
    timezone?: string;
    language?: string;
    languages?: string[];
    platform?: string;
    hardwareConcurrency?: number;
    deviceMemory?: number;
    cookieEnabled?: boolean;
    doNotTrack?: string | null;
  };
} => {
  if (typeof window === 'undefined') return {};

  const nav = navigator;
  const screen = window.screen;

  return {
    client: {
      screenWidth: screen?.width,
      screenHeight: screen?.height,
      viewportWidth: window.innerWidth,
      viewportHeight: window.innerHeight,
      devicePixelRatio: window.devicePixelRatio,
      timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
      language: nav.language,
      languages: nav.languages ? [...nav.languages] : undefined,
      platform: nav.platform,
      hardwareConcurrency: (nav as Navigator & { hardwareConcurrency?: number }).hardwareConcurrency,
      deviceMemory: (nav as Navigator & { deviceMemory?: number }).deviceMemory,
      cookieEnabled: nav.cookieEnabled,
      doNotTrack: nav.doNotTrack ?? null,
    },
  };
};

/**
 * Получить контекст (только серверные данные, вызывается с API route).
 */
export const fetchContext = async (): Promise<GeoDeviceContext> => {
  const res = await fetch(GEO_CONTEXT_API);
  if (!res.ok) throw new Error('Failed to fetch context');
  return res.json();
};

/**
 * Получить полный контекст с данными клиента (вызывать из браузера).
 */
export const fetchContextWithClient = async (): Promise<GeoDeviceContext> => {
  const clientData = collectClientData();

  const res = await fetch(GEO_CONTEXT_API, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(clientData),
  });

  if (!res.ok) throw new Error('Failed to fetch context');
  return res.json();
};

/**
 * С геолокацией из браузера (если пользователь разрешил).
 */
export const fetchContextWithGeolocation = async (): Promise<GeoDeviceContext> => {
  const clientData = collectClientData();

  return new Promise((resolve, reject) => {
    if (!navigator.geolocation) {
      fetchContextWithClient().then(resolve).catch(reject);
      return;
    }

    navigator.geolocation.getCurrentPosition(
      (position) => {
        const geo = {
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
        };
        fetch(GEO_CONTEXT_API, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ ...clientData, geo }),
        })
          .then((r) => r.json())
          .then(resolve)
          .catch(reject);
      },
      () => fetchContextWithClient().then(resolve).catch(reject),
    );
  });
};
