import { afterEach, describe, expect, it, vi } from 'vitest';
import { openAppScheme } from './openAppScheme';

// openAppScheme touches window/document/navigator; the suite runs in a plain node
// environment, so stub just enough of the DOM to observe which launch path is taken.
interface FakeIframe {
  style: { display: string };
  src: string;
  remove: () => void;
}

function setup(nav: { userAgent?: string; platform?: string; maxTouchPoints?: number }) {
  const location = { href: '' };
  const createdIframes: FakeIframe[] = [];

  vi.stubGlobal('navigator', {
    userAgent: nav.userAgent ?? '',
    platform: nav.platform ?? '',
    maxTouchPoints: nav.maxTouchPoints ?? 0,
  });
  vi.stubGlobal('window', {
    location,
    setTimeout: () => 0,
  });
  vi.stubGlobal('document', {
    body: { appendChild: () => undefined },
    createElement: () => {
      const iframe: FakeIframe = { style: { display: '' }, src: '', remove: () => undefined };
      createdIframes.push(iframe);
      return iframe;
    },
  });

  return { location, createdIframes };
}

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

  it('navigates directly for http(s) links (no iframe)', () => {
    const { location, createdIframes } = setup({ userAgent: 'Mozilla/5.0 (Android)' });
    openAppScheme('https://example.com/sub');
    expect(location.href).toBe('https://example.com/sub');
    expect(createdIframes).toHaveLength(0);
  });

  it('opens a custom scheme via top-level navigation on iOS (iPhone), not via iframe', () => {
    const { location, createdIframes } = setup({
      userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) Safari/605.1',
    });
    openAppScheme('incy://import/https://sp.example.com/abc');
    // iOS ignores iframe scheme launches — must be a real top-level navigation.
    expect(location.href).toBe('incy://import/https://sp.example.com/abc');
    expect(createdIframes).toHaveLength(0);
  });

  it('treats touch-capable iPadOS (reports as Mac) as iOS', () => {
    const { location, createdIframes } = setup({
      userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) Safari/605.1',
      platform: 'MacIntel',
      maxTouchPoints: 5,
    });
    openAppScheme('happ://add/https://sp.example.com/abc');
    expect(location.href).toBe('happ://add/https://sp.example.com/abc');
    expect(createdIframes).toHaveLength(0);
  });

  it('uses a contained iframe for custom schemes on Android (keeps page alive)', () => {
    const { location, createdIframes } = setup({
      userAgent: 'Mozilla/5.0 (Linux; Android 13) Chrome/120',
    });
    openAppScheme('incy://import/https://sp.example.com/abc');
    // Android in-app browsers would paint a full-page error on a top-level nav.
    expect(location.href).toBe('');
    expect(createdIframes).toHaveLength(1);
    expect(createdIframes[0].src).toBe('incy://import/https://sp.example.com/abc');
  });

  it('treats a non-touch Mac (desktop Safari) as non-iOS', () => {
    const { createdIframes } = setup({
      userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) Safari/605.1',
      platform: 'MacIntel',
      maxTouchPoints: 0,
    });
    openAppScheme('incy://import/https://sp.example.com/abc');
    expect(createdIframes).toHaveLength(1);
  });
});

describe('openAppScheme guard (defense-in-depth)', () => {
  afterEach(() => {
    vi.unstubAllGlobals();
  });

  it.each([
    'javascript:alert(1)',
    'javascript://%0aalert(1)',
    'data:text/html,<script>alert(1)</script>',
    'vbscript://x',
    'file:///etc/passwd',
    'intent://scan/#Intent;end',
    'no-scheme-at-all',
  ])('never navigates for dangerous input (%s)', (url) => {
    const { location, createdIframes } = setup({
      userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) Safari/605.1',
    });
    openAppScheme(url);
    expect(location.href).toBe('');
    expect(createdIframes).toHaveLength(0);
  });

  it('still opens valid app schemes after the guard', () => {
    const { location } = setup({
      userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) Safari/605.1',
    });
    openAppScheme('happ://add/https://sp.example.com/abc');
    expect(location.href).toBe('happ://add/https://sp.example.com/abc');
  });
});
