import { describe, it, expect, afterEach } from 'vitest';
import { isOverflowing, overflowTooltip } from './overflowTooltip';

// jsdom doesn't lay out, so scrollWidth/clientWidth are always 0. Stub them
// to model a clipped vs fitting element.
function makeEl(dims: {
    scrollWidth?: number;
    clientWidth?: number;
    scrollHeight?: number;
    clientHeight?: number;
}): HTMLElement {
    const el = document.createElement('span');
    for (const [k, v] of Object.entries(dims)) {
        Object.defineProperty(el, k, { configurable: true, value: v });
    }
    document.body.appendChild(el);
    return el;
}

afterEach(() => {
    document.body.innerHTML = '';
});

describe('isOverflowing', () => {
    it('is true when content is clipped horizontally', () => {
        expect(isOverflowing(makeEl({ scrollWidth: 200, clientWidth: 100 }))).toBe(true);
    });

    it('is true when content is clipped vertically (line-clamp)', () => {
        expect(
            isOverflowing(makeEl({ scrollWidth: 100, clientWidth: 100, scrollHeight: 80, clientHeight: 40 }))
        ).toBe(true);
    });

    it('is false when the content fits', () => {
        expect(isOverflowing(makeEl({ scrollWidth: 100, clientWidth: 100 }))).toBe(false);
    });
});

describe('overflowTooltip action', () => {
    it('sets a title with the text when the element is truncated', () => {
        const el = makeEl({ scrollWidth: 200, clientWidth: 100 });
        overflowTooltip(el, 'A very long manga title');
        expect(el.getAttribute('title')).toBe('A very long manga title');
    });

    it('does not set a title when the text fits', () => {
        const el = makeEl({ scrollWidth: 100, clientWidth: 100 });
        overflowTooltip(el, 'Short');
        expect(el.getAttribute('title')).toBeNull();
    });

    it('updates the title text when the bound value changes', () => {
        const el = makeEl({ scrollWidth: 200, clientWidth: 100 });
        const action = overflowTooltip(el, 'First');
        expect(el.getAttribute('title')).toBe('First');
        action.update('Second');
        expect(el.getAttribute('title')).toBe('Second');
    });
});
