import { afterEach, describe, expect, it, vi } from 'vitest';
import {
  insideVK,
  onVKPath,
  routeExternalLinkInVK,
  vkAndroidWebView,
  vkAppId,
  vkDiagLines,
  vkExternalBrowserUrl,
  vkLaunchDiag,
  vkLaunchParams,
  vkStartParam,
  appearanceForBg,
} from './vk';

describe('vk launch detection', () => {
  afterEach(() => vi.unstubAllGlobals());

  it('is not inside VK and not on the VK path without a location (node / SSR)', () => {
    expect(onVKPath()).toBe(false);
    expect(insideVK()).toBe(false);
    expect(vkLaunchParams()).toBe('');
  });

  it('detects the dedicated /vk/ entry path', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '' });
    expect(onVKPath()).toBe(true);
    vi.stubGlobal('location', { pathname: '/app/', search: '' });
    expect(onVKPath()).toBe(false);
  });

  it('returns the signed launch query only when a sign is present', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '?vk_user_id=1&vk_ts=2&sign=abc' });
    expect(vkLaunchParams()).toBe('vk_user_id=1&vk_ts=2&sign=abc');
    expect(insideVK()).toBe(true);
  });

  it('treats a URL carrying no sign as not a VK launch', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '?utm_source=catalog' });
    expect(vkLaunchParams()).toBe('');
    expect(insideVK()).toBe(false);
  });
});

describe('vk launch params', () => {
  afterEach(() => vi.unstubAllGlobals());

  it('reads the VK app id from the launch query', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '?vk_app_id=6736218&sign=x' });
    expect(vkAppId()).toBe('6736218');
  });

  it('reads the direct-link deep-link payload from the hash query param', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '?vk_user_id=1&sign=x&hash=f123456' });
    expect(vkStartParam()).toBe('f123456');
  });

  it('returns empty app id / start param when absent', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '?vk_user_id=1&sign=x' });
    expect(vkAppId()).toBe('');
    expect(vkStartParam()).toBe('');
  });
});

describe('vk external links', () => {
  afterEach(() => vi.unstubAllGlobals());

  function stubVK(platform: string) {
    const open = vi.fn();
    vi.stubGlobal('location', {
      pathname: '/vk/',
      search: `?vk_user_id=1&vk_platform=${platform}&sign=x`,
      href: 'https://app.example/vk/',
      origin: 'https://app.example',
    });
    vi.stubGlobal('window', { open });
    return open;
  }

  it('wraps a URL in the away.php redirect with the target encoded', () => {
    const url = 'https://gramota.ru/poisk?query=кот&mode=slovari';
    expect(vkExternalBrowserUrl(url)).toBe(`https://vk.com/away.php?to=${encodeURIComponent(url)}`);
  });

  it('detects the Android VK WebView from vk_platform', () => {
    stubVK('mobile_android');
    expect(vkAndroidWebView()).toBe(true);
    stubVK('mobile_android_messenger');
    expect(vkAndroidWebView()).toBe(true);
    stubVK('mobile_iphone');
    expect(vkAndroidWebView()).toBe(false);
    stubVK('desktop_web');
    expect(vkAndroidWebView()).toBe(false);
  });

  it('is not the Android WebView without a signed VK launch', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '?vk_platform=mobile_android' });
    expect(vkAndroidWebView()).toBe(false);
  });

  it('routes an external _blank link through the away redirect on Android', () => {
    const open = stubVK('mobile_android');
    expect(routeExternalLinkInVK({ href: 'https://gramota.ru/poisk?query=кот', target: '_blank' })).toBe(true);
    expect(open).toHaveBeenCalledWith(
      `https://vk.com/away.php?to=${encodeURIComponent('https://gramota.ru/poisk?query=кот')}`,
      '_blank',
    );
  });

  it('leaves same-origin and non-_blank links to the browser', () => {
    const open = stubVK('mobile_android');
    expect(routeExternalLinkInVK({ href: 'https://app.example/lobby', target: '_blank' })).toBe(false);
    expect(routeExternalLinkInVK({ href: 'https://gramota.ru', target: '' })).toBe(false);
    expect(open).not.toHaveBeenCalled();
  });

  it('does nothing outside the Android VK client (iOS / desktop open _blank fine)', () => {
    const open = stubVK('mobile_iphone');
    expect(routeExternalLinkInVK({ href: 'https://gramota.ru', target: '_blank' })).toBe(false);
    expect(open).not.toHaveBeenCalled();
  });
});

describe('vkDiagLines (launch diagnostic)', () => {
  it('reports an unsigned browser open: no sign, every VK param missing', () => {
    const lines = vkDiagLines('utm_source=catalog', false, '');
    expect(lines[0]).toBe('launch: unsigned   iframe: no');
    expect(lines[1]).toBe('vk-platform: —');
    expect(lines[2]).toBe('params: utm_source');
    expect(lines[3]).toBe('missing: vk_app_id,vk_user_id,vk_ts,vk_platform,sign');
    expect(lines[4]).toBe('referrer: —');
  });

  it('reports a signed launch and never leaks the sign value, only its name', () => {
    const lines = vkDiagLines(
      'vk_app_id=6736218&vk_platform=mobile_android&vk_user_id=42&vk_ts=1700000000&sign=SECRETSIG',
      true,
      'vk.com',
    );
    expect(lines[0]).toBe('launch: signed   iframe: yes');
    expect(lines[1]).toBe('vk-platform: mobile_android');
    expect(lines[3]).toBe('missing: —');
    expect(lines[4]).toBe('referrer: vk.com');
    // The signature is auth material: its NAME may appear, its VALUE must never.
    const report = lines.join('\n');
    expect(report).toContain('sign');
    expect(report).not.toContain('SECRETSIG');
  });
});

describe('vkLaunchDiag', () => {
  afterEach(() => vi.unstubAllGlobals());

  it('builds a VK launch diagnostic with no Retry (VK signs the URL at load, nothing to wait for)', () => {
    vi.stubGlobal('location', { pathname: '/vk/', search: '?utm_source=catalog' });
    const d = vkLaunchDiag();
    expect(d.platform).toBe('vk');
    expect(d.retry).toBe(false);
    expect(d.report).toContain('launch: unsigned');
  });
});

describe('appearanceForBg', () => {
  it('maps a dark background to the dark appearance (light status-bar icons)', () => {
    expect(appearanceForBg('#0f1115')).toBe('dark');
    expect(appearanceForBg('#171a21')).toBe('dark');
  });

  it('maps a light background to the light appearance (dark status-bar icons)', () => {
    expect(appearanceForBg('#f3f4f6')).toBe('light');
    expect(appearanceForBg('#ffffff')).toBe('light');
  });

  it('accepts shorthand hex and surrounding whitespace (a raw CSS custom-property value)', () => {
    expect(appearanceForBg('#000')).toBe('dark');
    expect(appearanceForBg('  #fff  ')).toBe('light');
  });

  it('defaults to light for an unparseable colour', () => {
    expect(appearanceForBg('')).toBe('light');
    expect(appearanceForBg('rgb(0, 0, 0)')).toBe('light');
  });
});
