import { describe, expect, it } from 'vitest';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import TimesheetCell from './TimesheetCell.vue';
import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time';
import type { TimesheetCell as TimesheetCellType } from '@/utils/useTimesheetGrid';

function buildCell(totalSeconds: number): TimesheetCellType {
    return {
        dayIndex: 0,
        date: '2026-04-13',
        entries: [],
        totalSeconds,
    };
}

function mountTimesheetCell(totalSeconds = 2 * 3600) {
    return mount(TimesheetCell, {
        props: {
            cell: buildCell(totalSeconds),
            dayIndex: 0,
            date: '2026-04-13',
            isToday: false,
            hasRunningEntry: false,
        },
    });
}

describe('TimesheetCell', () => {
    it('emits 0 when the cleared value is committed on blur', async () => {
        const wrapper = mountTimesheetCell();
        const input = wrapper.get('input');

        await input.trigger('focus');
        await input.setValue('');
        await input.trigger('blur');

        expect(wrapper.emitted('update')).toEqual([[0]]);
    });

    it('emits 0 when the cleared value is committed with Enter', async () => {
        const wrapper = mountTimesheetCell();
        const input = wrapper.get('input');

        await input.trigger('focus');
        await input.setValue('');
        await input.trigger('keydown', { key: 'Enter' });

        expect(wrapper.emitted('update')).toEqual([[0]]);
    });

    it('restores the previous value and emits nothing on Escape', async () => {
        const wrapper = mountTimesheetCell();
        const input = wrapper.get('input');
        const previousValue = formatHumanReadableDuration(2 * 3600, 'hours-minutes', 'point');

        await input.trigger('focus');
        await input.setValue('');
        await input.trigger('keydown', { key: 'Escape' });
        await nextTick();

        expect(wrapper.emitted('update')).toBeUndefined();
        expect((input.element as HTMLInputElement).value).toBe(previousValue);
    });

    it('shows a pending 0 (delete in flight) over the cell total', () => {
        const wrapper = mount(TimesheetCell, {
            props: {
                cell: buildCell(2 * 3600),
                dayIndex: 0,
                date: '2026-04-13',
                isToday: false,
                hasRunningEntry: false,
                pendingSeconds: 0,
            },
        });

        // `??` (not `||`): a pending 0 must win over the 2h cell total.
        expect((wrapper.get('input').element as HTMLInputElement).value).toBe('');
    });

    it('disables editing while the cell is saving', () => {
        const wrapper = mount(TimesheetCell, {
            props: {
                cell: buildCell(2 * 3600),
                dayIndex: 0,
                date: '2026-04-13',
                isToday: false,
                hasRunningEntry: false,
                saveStatus: 'saving',
            },
        });

        expect((wrapper.get('input').element as HTMLInputElement).disabled).toBe(true);
    });

    it('renders read-only and emits nothing when the row is read-only', async () => {
        const wrapper = mount(TimesheetCell, {
            props: {
                cell: buildCell(2 * 3600),
                dayIndex: 0,
                date: '2026-04-13',
                isToday: false,
                hasRunningEntry: false,
                readonly: true,
            },
        });

        const input = wrapper.get('input');
        expect((input.element as HTMLInputElement).disabled).toBe(true);

        await input.trigger('focus');
        await input.setValue('4h');
        await input.trigger('blur');

        expect(wrapper.emitted('update')).toBeUndefined();
    });
});
