import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
  isPushSupported,
  isStandalonePWA,
  isIOS,
  urlBase64ToUint8Array,
} from './push-subscribe';

describe('isPushSupported', () => {
  beforeEach(() => {
    // Reset to a sane baseline for each test.
    delete (globalThis as any).window;
    delete (globalThis as any).navigator;
  });

  it('returns false when window is missing', () => {
    expect(isPushSupported()).toBe(false);
  });

  it('returns true when SW + PushManager + Notification are present', () => {
    (globalThis as any).window = { PushManager: function () {}, Notification: function () {} };
    (globalThis as any).navigator = { serviceWorker: {} };
    expect(isPushSupported()).toBe(true);
  });

  it('returns false when PushManager is missing', () => {
    (globalThis as any).window = { Notification: function () {} };
    (globalThis as any).navigator = { serviceWorker: {} };
    expect(isPushSupported()).toBe(false);
  });
});

describe('isStandalonePWA', () => {
  beforeEach(() => {
    delete (globalThis as any).window;
    delete (globalThis as any).navigator;
  });

  it('returns true when display-mode standalone matches', () => {
    (globalThis as any).window = {
      matchMedia: vi.fn().mockReturnValue({ matches: true }),
    };
    (globalThis as any).navigator = {};
    expect(isStandalonePWA()).toBe(true);
  });

  it('returns true on iOS Safari with navigator.standalone', () => {
    (globalThis as any).window = {
      matchMedia: vi.fn().mockReturnValue({ matches: false }),
    };
    (globalThis as any).navigator = { standalone: true };
    expect(isStandalonePWA()).toBe(true);
  });

  it('returns false in a normal tab', () => {
    (globalThis as any).window = {
      matchMedia: vi.fn().mockReturnValue({ matches: false }),
    };
    (globalThis as any).navigator = {};
    expect(isStandalonePWA()).toBe(false);
  });
});

describe('isIOS', () => {
  beforeEach(() => {
    delete (globalThis as any).navigator;
  });

  it('detects iPhone', () => {
    (globalThis as any).navigator = { userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 ...)' };
    expect(isIOS()).toBe(true);
  });

  it('detects iPad', () => {
    (globalThis as any).navigator = { userAgent: 'Mozilla/5.0 (iPad; CPU OS 17_4 ...)' };
    expect(isIOS()).toBe(true);
  });

  it('detects modern iPadOS (reports as Mac with touch points)', () => {
    (globalThis as any).navigator = {
      userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
      maxTouchPoints: 5,
    };
    expect(isIOS()).toBe(true);
  });

  it('returns false for non-Mac, non-iOS', () => {
    (globalThis as any).navigator = {
      userAgent: 'Mozilla/5.0 (Windows NT 10.0)',
      maxTouchPoints: 0,
    };
    expect(isIOS()).toBe(false);
  });

  it('returns false for desktop Mac (no touch points)', () => {
    (globalThis as any).navigator = {
      userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
      maxTouchPoints: 0,
    };
    expect(isIOS()).toBe(false);
  });
});

describe('urlBase64ToUint8Array', () => {
  it('decodes standard base64url', () => {
    // "Hello" => "SGVsbG8" (base64url without padding)
    const result = urlBase64ToUint8Array('SGVsbG8');
    expect(Array.from(result)).toEqual([72, 101, 108, 108, 111]);
  });

  it('handles base64url with - and _', () => {
    // "??" in base64 is "Pz8="; base64url is "Pz8" with - and _ unused here.
    // Use a longer value with - and _ to exercise replacement:
    // Build a small payload deterministically.
    const bytes = new Uint8Array([0xfb, 0xff, 0xbe]);
    // base64 of [0xfb, 0xff, 0xbe] = "+/++", base64url = "-_--"
    const result = urlBase64ToUint8Array('-_--');
    expect(Array.from(result)).toEqual(Array.from(bytes));
  });

  it('pads correctly when input length is not a multiple of 4', () => {
    // "M" in base64 is "TQ==", base64url "TQ" (length 2 → pad 2)
    const result = urlBase64ToUint8Array('TQ');
    expect(Array.from(result)).toEqual([0x4d]);
  });
});
