import { buildImageActionTarget, formatLogTime, ImageOutput } from './image-output';
import { I18nProvider } from '@/lib/i18n';
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { renderToStaticMarkup } from 'react-dom/server';

const noop = () => {};
const buttonContentPattern = '[\\s\\S]*?';

function renderImageOutput(viewMode: 'grid' | number): string {
    return renderToStaticMarkup(
        <I18nProvider>
            <ImageOutput
                imageBatch={[
                    { path: '/api/image/first.png', filename: 'first.png' },
                    { path: '/api/image/second.png', filename: 'second.png' }
                ]}
                viewMode={viewMode}
                onViewChange={noop}
                isLoading={false}
                onSendToEdit={noop}
                onDownloadImage={noop}
                onShareImage={noop}
                onCreateVariant={noop}
                onReusePrompt={noop}
                canCreateVariant
                canReusePrompt
                currentMode='generate'
                baseImagePreviewUrl={null}
                clientPasswordHash={null}
                canOpenLogs={false}
            />
        </I18nProvider>
    );
}

describe('ImageOutput result actions', () => {
    it('does not show fixed preview timing or dimensions before real image metadata is known', () => {
        const html = renderImageOutput(0);

        assert.match(html, /第 1 张 \/ 共 2 张/);
        assert.doesNotMatch(html, /预计 8-12 秒/);
        assert.doesNotMatch(html, /1024 x 768/);
    });

    it('uses the localized generated-image alt text when a caller does not override it', () => {
        const html = renderImageOutput(0);

        assert.match(html, /alt="生成图片输出"/);
        assert.doesNotMatch(html, /Generated image output/);
    });

    it('formats activity timestamps with the selected app locale and preserves invalid diagnostic values', () => {
        const timestamp = '2026-05-31T12:15:30.000Z';

        assert.equal(formatLogTime(timestamp, 'zh-CN'), new Date(timestamp).toLocaleTimeString('zh-CN'));
        assert.equal(formatLogTime(timestamp, 'en-US'), new Date(timestamp).toLocaleTimeString('en-US'));
        assert.equal(formatLogTime('not-a-timestamp', 'zh-CN'), 'not-a-timestamp');
    });

    it('uses the no-image state in the preview header before generation', () => {
        const html = renderToStaticMarkup(
            <I18nProvider>
                <ImageOutput
                    imageBatch={null}
                    viewMode='grid'
                    onViewChange={noop}
                    isLoading={false}
                    onSendToEdit={noop}
                    onDownloadImage={noop}
                    onShareImage={noop}
                    onCreateVariant={noop}
                    onReusePrompt={noop}
                    canCreateVariant={false}
                    canReusePrompt={false}
                    currentMode='generate'
                    baseImagePreviewUrl={null}
                    clientPasswordHash={null}
                    canOpenLogs={false}
                />
            </I18nProvider>
        );

        assert.match(html, /还没有生成图像/);
        assert.match(html, /写下灵感后点击生成/);
        assert.match(html, /workbench-panel[^"]*h-fit xl:h-full[\s\S]*preview-gallery-board/);
        assert.match(html, /min-h-\[220px\] shrink-0 sm:min-h-\[248px\] lg:min-h-\[272px\] xl:min-h-0 xl:flex-1/);
        assert.doesNotMatch(html, /min-h-\[20rem\]/);
        assert.match(html, /max-w-\[30rem\]/);
        assert.match(html, /items-center justify-center/);
        assert.match(html, /text-center/);
        assert.doesNotMatch(html, /2xl:max-w-\[34rem\]/);
        assert.doesNotMatch(html, /photo-paper relative flex aspect-\[8\/5\]/);
        assert.doesNotMatch(html, /max-w-\[780px\] flex-col justify-between/);
        assert.doesNotMatch(html, /<img/);
        assert.doesNotMatch(html, /workbench-sample/);
        assert.doesNotMatch(html, /灵感样张/);
        assert.doesNotMatch(html, /1024 x 768/);
        for (const action of ['继续编辑', '按相同参数再次生成', '复用提示词', '对比', '下载']) {
            assert.match(
                html,
                new RegExp(
                    `<button[^>]*disabled=""[^>]*>${buttonContentPattern}${action}${buttonContentPattern}</button>`
                )
            );
        }
    });

    it('keeps the full preview stage height after images exist', () => {
        const html = renderImageOutput(0);

        assert.match(html, /workbench-panel[^"]*h-full[\s\S]*preview-gallery-board/);
        assert.match(html, /min-h-\[300px\] flex-1 sm:min-h-\[420px\] lg:min-h-\[520px\]/);
        assert.doesNotMatch(html, /min-h-\[220px\] shrink-0 sm:min-h-\[248px\] lg:min-h-\[272px\]/);
    });

    it('uses an edit reference placeholder instead of the sample image in edit mode', () => {
        const html = renderToStaticMarkup(
            <I18nProvider>
                <ImageOutput
                    imageBatch={null}
                    viewMode='grid'
                    onViewChange={noop}
                    isLoading={false}
                    onSendToEdit={noop}
                    onDownloadImage={noop}
                    onShareImage={noop}
                    onCreateVariant={noop}
                    onReusePrompt={noop}
                    canCreateVariant={false}
                    canReusePrompt={false}
                    currentMode='edit'
                    baseImagePreviewUrl={null}
                    clientPasswordHash={null}
                    canOpenLogs={false}
                />
            </I18nProvider>
        );

        assert.match(html, /先放入参考图/);
        assert.match(html, /等待参考图/);
        assert.doesNotMatch(html, /min-h-\[18rem\]/);
        assert.match(html, /max-w-\[30rem\]/);
        assert.doesNotMatch(html, /photo-paper relative flex aspect-\[4\/3\]/);
        assert.doesNotMatch(html, /灵感样张/);
    });

    it('shows the edit reference image before an edit result exists', () => {
        const html = renderToStaticMarkup(
            <I18nProvider>
                <ImageOutput
                    imageBatch={null}
                    viewMode='grid'
                    onViewChange={noop}
                    isLoading={false}
                    onSendToEdit={noop}
                    onDownloadImage={noop}
                    onShareImage={noop}
                    onCreateVariant={noop}
                    onReusePrompt={noop}
                    canCreateVariant={false}
                    canReusePrompt={false}
                    currentMode='edit'
                    baseImagePreviewUrl='data:image/png;base64,reference'
                    clientPasswordHash={null}
                    canOpenLogs={false}
                />
            </I18nProvider>
        );

        assert.match(html, /参考图已就绪/);
        assert.match(html, /图生图参考图预览/);
        assert.match(html, /参考图/);
        assert.doesNotMatch(html, /灵感样张/);
    });

    it('requires an explicit selection before single-image actions in the multi-image grid view', () => {
        const html = renderImageOutput('grid');

        assert.match(html, /aria-label="选择第 1 张图片"/);
        assert.match(html, /aria-label="选择第 2 张图片"/);
        assert.match(html, /请选择一张图片/);
        assert.doesNotMatch(html, /第 1 张 \/ 共 2 张/);

        for (const action of ['继续编辑', '对比', '下载', '分享']) {
            assert.match(
                html,
                new RegExp(
                    `<button[^>]*disabled=""[^>]*>${buttonContentPattern}${action}${buttonContentPattern}</button>`
                )
            );
        }
    });

    it('keeps single-image actions available after selecting a multi-image result', () => {
        const html = renderImageOutput(1);

        assert.match(html, /第 2 张 \/ 共 2 张/);

        for (const action of ['继续编辑', '对比', '下载', '分享']) {
            assert.match(
                html,
                new RegExp(`<button[^>]*>${buttonContentPattern}${action}${buttonContentPattern}</button>`)
            );
            assert.doesNotMatch(
                html,
                new RegExp(
                    `<button[^>]*disabled=""[^>]*>${buttonContentPattern}${action}${buttonContentPattern}</button>`
                )
            );
        }
    });

    it('builds selected image action targets with storage mode', () => {
        assert.deepEqual(
            buildImageActionTarget({
                path: 'data:image/png;base64,selected',
                filename: 'selected.png',
                storageMode: 'indexeddb'
            }),
            { filename: 'selected.png', storageMode: 'indexeddb' }
        );
        assert.deepEqual(
            buildImageActionTarget({
                path: '/api/image/fs.png',
                filename: 'fs.png'
            }),
            { filename: 'fs.png' }
        );
        assert.equal(buildImageActionTarget(null), null);
    });

    it('keeps compare disabled for single-image results', () => {
        const html = renderToStaticMarkup(
            <I18nProvider>
                <ImageOutput
                    imageBatch={[{ path: '/api/image/only.png', filename: 'only.png' }]}
                    viewMode={0}
                    onViewChange={noop}
                    isLoading={false}
                    onSendToEdit={noop}
                    onDownloadImage={noop}
                    onShareImage={noop}
                    onCreateVariant={noop}
                    onReusePrompt={noop}
                    canCreateVariant
                    canReusePrompt
                    currentMode='generate'
                    baseImagePreviewUrl={null}
                    clientPasswordHash={null}
                    canOpenLogs={false}
                />
            </I18nProvider>
        );

        assert.match(
            html,
            new RegExp(`<button[^>]*disabled=""[^>]*>${buttonContentPattern}对比${buttonContentPattern}</button>`)
        );
    });

    it('enables compare for single-image results with a previous history image', () => {
        const html = renderToStaticMarkup(
            <I18nProvider>
                <ImageOutput
                    imageBatch={[{ path: '/api/image/only.png', filename: 'only.png' }]}
                    compareImage={{ path: '/api/image/previous.png', filename: 'previous.png' }}
                    viewMode={0}
                    onViewChange={noop}
                    isLoading={false}
                    onSendToEdit={noop}
                    onDownloadImage={noop}
                    onShareImage={noop}
                    onCreateVariant={noop}
                    onReusePrompt={noop}
                    canCreateVariant
                    canReusePrompt
                    currentMode='generate'
                    baseImagePreviewUrl={null}
                    clientPasswordHash={null}
                    canOpenLogs={false}
                />
            </I18nProvider>
        );

        assert.match(
            html,
            new RegExp(`<button(?![^>]*disabled="")[^>]*>${buttonContentPattern}对比${buttonContentPattern}</button>`)
        );
    });

    it('uses user-facing generation activity copy for the activity entry', () => {
        const html = renderToStaticMarkup(
            <I18nProvider>
                <ImageOutput
                    imageBatch={[{ path: '/api/image/only.png', filename: 'only.png' }]}
                    viewMode={0}
                    onViewChange={noop}
                    isLoading={false}
                    onSendToEdit={noop}
                    onDownloadImage={noop}
                    onShareImage={noop}
                    onCreateVariant={noop}
                    onReusePrompt={noop}
                    canCreateVariant
                    canReusePrompt
                    currentMode='generate'
                    baseImagePreviewUrl={null}
                    clientPasswordHash='test-hash'
                    canOpenLogs
                />
            </I18nProvider>
        );

        assert.match(html, /查看动态/);
        assert.doesNotMatch(html, /查看日志/);
    });

    it('shows an explicit failure state with retry near the canvas', () => {
        const html = renderToStaticMarkup(
            <I18nProvider>
                <ImageOutput
                    imageBatch={null}
                    viewMode='grid'
                    onViewChange={noop}
                    isLoading={false}
                    onSendToEdit={noop}
                    onDownloadImage={noop}
                    onShareImage={noop}
                    onCreateVariant={noop}
                    onReusePrompt={noop}
                    failureMessage='上游或 API 中转站异常。请稍后重试。'
                    onRetry={noop}
                    canCreateVariant={false}
                    canReusePrompt={false}
                    currentMode='generate'
                    baseImagePreviewUrl={null}
                    clientPasswordHash={null}
                    canOpenLogs={false}
                />
            </I18nProvider>
        );

        assert.match(html, /生成失败/);
        assert.match(html, /上游或 API 中转站异常。请稍后重试。/);
        assert.match(html, new RegExp(`<button[^>]*>${buttonContentPattern}重试生成${buttonContentPattern}</button>`));
        assert.doesNotMatch(html, /灵感样张/);
    });
});
