// localStorage stub — must be set before importing app.js
let _localStorageStore = {};
globalThis.localStorage = {
  getItem: (key) => (Object.prototype.hasOwnProperty.call(_localStorageStore, key) ? _localStorageStore[key] : null),
  setItem: (key, value) => { _localStorageStore[key] = String(value); },
  removeItem: (key) => { delete _localStorageStore[key]; },
};

// Browser global stubs — must be set before importing app.js
globalThis.document = {
  getElementById: () => null,
  querySelector: () => null,
  querySelectorAll: () => [],
  createElement: () => ({ style: {}, classList: { add: () => {}, remove: () => {} } }),
  addEventListener: () => {},
  removeEventListener: () => {},
};

// Stubs for functions called by pollSessions (implemented in later tasks)
globalThis.renderGrid = () => {};
globalThis.handleBellTransitions = () => {};
globalThis.openSession = () => {};
globalThis.updatePillBell = () => {};

globalThis.window = {
  addEventListener: () => {},
  location: { href: '' },
  innerWidth: 1024,
};

globalThis.Notification = {
  permission: 'default',
  requestPermission: async () => 'default',
};

// navigator is read-only in Node v24+, use defineProperty
Object.defineProperty(globalThis, 'navigator', {
  value: { userAgent: 'test-agent' },
  writable: true,
  configurable: true,
});

import { createRequire } from 'node:module';
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const require = createRequire(import.meta.url);
const app = require(join(__dirname, '..', 'app.js'));

// Helper: returns a mock DOM element with querySelector support
function mockEl() {
  return { textContent: '', style: {}, classList: { remove: () => {}, add: () => {} }, querySelector: () => null };
}

// --- Task 12: openSession should NOT POST /connect for local sessions ---

test('openSession for local session does NOT POST to /connect', async () => {
  const fetchCalls = [];
  const origFetch = globalThis.fetch;
  const origGetById = globalThis.document.getElementById;
  const origQS = globalThis.document.querySelector;
  const origSetTimeout = globalThis.setTimeout;
  globalThis.fetch = async (url, opts) => { fetchCalls.push({ url, opts }); return { ok: true }; };
  globalThis.document.getElementById = () => mockEl();
  globalThis.document.querySelector = () => null;
  globalThis.setTimeout = () => {};
  globalThis.window._openTerminal = () => {};

  await app.openSession('local-session', {});

  // Local sessions should NOT POST to /api/sessions/{name}/connect
  const connectCall = fetchCalls.find((c) => c.url === '/api/sessions/local-session/connect');
  assert.ok(!connectCall, 'local session should NOT POST to /api/sessions/{name}/connect');
  globalThis.fetch = origFetch;
  globalThis.document.getElementById = origGetById;
  globalThis.document.querySelector = origQS;
  globalThis.setTimeout = origSetTimeout;
});

test('openSession for remote session still POSTs to federation connect', async () => {
  const fetchCalls = [];
  const origFetch = globalThis.fetch;
  const origGetById = globalThis.document.getElementById;
  const origQS = globalThis.document.querySelector;
  const origSetTimeout = globalThis.setTimeout;
  globalThis.fetch = async (url, opts) => { fetchCalls.push({ url, opts }); return { ok: true }; };
  globalThis.document.getElementById = () => mockEl();
  globalThis.document.querySelector = () => null;
  globalThis.setTimeout = () => {};
  globalThis.window._openTerminal = () => {};

  await app.openSession('work-project', { remoteId: 'fed-abc123' });

  const connectCall = fetchCalls.find((c) => c.url === '/api/federation/fed-abc123/connect/work-project');
  assert.ok(connectCall, 'remote session should POST to federation connect');
  assert.strictEqual(connectCall.opts.method, 'POST');
  globalThis.fetch = origFetch;
  globalThis.document.getElementById = origGetById;
  globalThis.document.querySelector = origQS;
  globalThis.setTimeout = origSetTimeout;
});

test('openSession for remote session shows toast and closes on federation connect failure', async () => {
  let closeTerminalCalled = false;
  let toastMsg = '';
  const mockToast = { show: (msg) => { toastMsg = msg; }, textContent: '', classList: { remove: () => {}, add: () => {} }, querySelector: () => null };
  const origFetch = globalThis.fetch;
  const origGetById = globalThis.document.getElementById;
  const origQS = globalThis.document.querySelector;
  const origSetTimeout = globalThis.setTimeout;
  globalThis.fetch = async (url) => {
    if (url.includes('/connect')) throw new Error('Connection failed');
    return { ok: true };
  };
  globalThis.document.getElementById = (id) => {
    if (id === 'toast') return mockToast;
    return mockEl();
  };
  globalThis.document.querySelector = () => null;
  globalThis.setTimeout = () => {};
  globalThis.window._openTerminal = () => {};
  globalThis.window._closeTerminal = () => { closeTerminalCalled = true; };

  // Use a remote session so /connect is actually called
  await app.openSession('failing-session', { remoteId: 'fed-xyz' });

  assert.ok(toastMsg.length > 0, 'toast should show an error message');
  assert.ok(closeTerminalCalled, 'closeSession should be called (_closeTerminal invoked)');
  globalThis.fetch = origFetch;
  globalThis.document.getElementById = origGetById;
  globalThis.document.querySelector = origQS;
  globalThis.setTimeout = origSetTimeout;
});

// --- Task 12: closeSession should NOT fire DELETE /api/sessions/current ---

test('closeSession does NOT fire DELETE /api/sessions/current for local session', async () => {
  const origFetch = globalThis.fetch;
  const origGetById = globalThis.document.getElementById;
  const origQS = globalThis.document.querySelector;
  const origSetTimeout = globalThis.setTimeout;

  // Setup to call openSession for a local session (no remoteId)
  globalThis.fetch = async () => ({ ok: true });
  globalThis.document.getElementById = () => mockEl();
  globalThis.document.querySelector = () => null;
  globalThis.setTimeout = () => {};
  globalThis.window._openTerminal = () => {};
  globalThis.window._closeTerminal = () => {};

  // Open a local session - this sets _viewingRemoteId = ''
  await app.openSession('local-sess', {});

  // Restore setTimeout so Promise-based yielding works
  globalThis.setTimeout = origSetTimeout;

  // Reset fetch tracking
  const fetchCalls = [];
  globalThis.fetch = async (url, opts) => { fetchCalls.push({ url, opts }); return { ok: true }; };

  // Close session
  await app.closeSession();
  // yield microtask queue for any fire-and-forget calls
  await new Promise((r) => setTimeout(r, 0));

  const deleteCall = fetchCalls.find((c) => c.url === '/api/sessions/current' && c.opts && c.opts.method === 'DELETE');
  assert.ok(!deleteCall, 'closeSession should NOT fire DELETE /api/sessions/current — detach is handled by closeTerminal()');

  globalThis.fetch = origFetch;
  globalThis.document.getElementById = origGetById;
  globalThis.document.querySelector = origQS;
  globalThis.setTimeout = origSetTimeout;
});
