import { assertEquals } from '@std/assert';

// Stimulus's Controller base class constructor only does `this.context = context`
// (see @hotwired/stimulus dist/stimulus.js), and none of this controller's methods
// touch Stimulus-specific getters (element/scope/targets), so a plain `{}` context
// is enough to construct a real instance. `document`/`sessionStorage` are stubbed
// since Deno has no browser DOM.
class FakeClassList {
    classes = new Set<string>();
    toggle(name: string, force?: boolean) {
        const shouldAdd = force ?? !this.classes.has(name);
        if (shouldAdd) this.classes.add(name);
        else this.classes.delete(name);
    }
    contains(name: string) {
        return this.classes.has(name);
    }
}

const classList = new FakeClassList();
let fullscreenElement: unknown = null;
const sessionStore = new Map<string, string>();

// deno-lint-ignore no-explicit-any
(globalThis as any).document = {
    documentElement: { classList },
    get fullscreenElement() {
        return fullscreenElement;
    },
    addEventListener: () => {},
    removeEventListener: () => {},
};
// Deno defines a native `sessionStorage` accessor on globalThis (get/set pair), so a
// plain assignment would just call through to it instead of replacing it — redefine
// the property outright.
Object.defineProperty(globalThis, 'sessionStorage', {
    value: {
        getItem: (key: string) => sessionStore.get(key) ?? null,
        setItem: (key: string, value: string) => sessionStore.set(key, value),
    },
    configurable: true,
});

const { default: FullscreenController } = await import(
    './fullscreen_controller.ts'
);

// deno-lint-ignore no-explicit-any
function makeController(): any {
    return new FullscreenController({} as never);
}

Deno.test('syncState adds is-fullscreen when a fullscreen element is set', () => {
    fullscreenElement = { tagName: 'HTML' };
    makeController().syncState();
    assertEquals(classList.contains('is-fullscreen'), true);
});

Deno.test('syncState removes is-fullscreen when there is no fullscreen element', () => {
    fullscreenElement = null;
    makeController().syncState();
    assertEquals(classList.contains('is-fullscreen'), false);
});

Deno.test('onFullscreenChange persists the fullscreen state and syncs classes', () => {
    fullscreenElement = { tagName: 'HTML' };
    makeController().onFullscreenChange();
    assertEquals(sessionStore.get('tvdt-fullscreen'), '1');
    assertEquals(classList.contains('is-fullscreen'), true);

    fullscreenElement = null;
    makeController().onFullscreenChange();
    assertEquals(sessionStore.get('tvdt-fullscreen'), '0');
    assertEquals(classList.contains('is-fullscreen'), false);
});
