import { render, waitFor } from '@testing-library/react';
import { SWRConfig } from 'swr';
import { describe, expect, it, vi, beforeEach } from 'vitest';
import { fetchClient } from '@ablogcms/fetch-client';
import { useSettingsContext } from '@ablogcms/block-editor/editor-settings';
import { DEFAULT_EDITOR_SETTINGS } from '@ablogcms/block-editor/normalize-settings';
import type { BlockDefinition } from '@ablogcms/block-editor/types';
import BlockEditorSettingsProvider from './block-editor-settings-provider';

const wrapper = ({ children }: { children: React.ReactNode }) => (
  <SWRConfig value={{ provider: () => new Map() }}>{children}</SWRConfig>
);

vi.mock('@ablogcms/fetch-client', () => ({
  fetchClient: { get: vi.fn() },
}));

function ContextConsumer() {
  const settings = useSettingsContext();
  return (
    <>
      <span data-testid="color-palette">{JSON.stringify(settings.colorPalette)}</span>
      <span data-testid="block-menu-command-name">{settings.blockMenus[0]?.commands[0]?.name ?? ''}</span>
    </>
  );
}

describe('BlockEditorSettingsProvider', () => {
  beforeEach(() => {
    vi.mocked(fetchClient.get).mockReset();
    (window as unknown as { ACMS: { Config: Record<string, unknown>; Library: unknown } }).ACMS.Config = {
      bid: 10,
      cid: 20,
    };
    (window as unknown as { ACMS: { Library: unknown } }).ACMS.Library = {
      acmsLink: vi.fn(() => 'ajax/edit/block-editor/settings.json'),
    };
  });

  it('取得前は既定値 (DEFAULT_EDITOR_SETTINGS) を子孫の Context に渡す', () => {
    vi.mocked(fetchClient.get).mockReturnValue(new Promise(() => {}));

    const { getByTestId } = render(
      <BlockEditorSettingsProvider>
        <ContextConsumer />
      </BlockEditorSettingsProvider>,
      { wrapper }
    );

    expect(getByTestId('color-palette').textContent).toBe(JSON.stringify(DEFAULT_EDITOR_SETTINGS.colorPalette));
  });

  it('取得した EditorSettings を子孫の Context 経由で渡す', async () => {
    vi.mocked(fetchClient.get).mockResolvedValueOnce({
      data: { colorPalette: ['#00ff00'] },
      status: 200,
      statusText: 'OK',
      headers: new Headers(),
    });

    const { getByTestId } = render(
      <BlockEditorSettingsProvider>
        <ContextConsumer />
      </BlockEditorSettingsProvider>,
      { wrapper }
    );

    await waitFor(() => {
      expect(getByTestId('color-palette').textContent).toBe('["#00ff00"]');
    });
  });

  it('blockDefinitions を渡すと useBlockEditorSettingsSWR の第2引数として渡り、プラグイン提供の type が blockMenus に残る', async () => {
    const calloutDef: BlockDefinition = {
      label: 'コールアウト',
      description: 'コールアウト',
      icon: 'title',
      isTextMenu: false,
      aliases: [],
      createActions: () => ({ action: () => {}, convert: () => {}, isDisabled: () => false, isActive: () => false }),
    };
    vi.mocked(fetchClient.get).mockResolvedValueOnce({
      data: { blockMenus: [{ type: 'callout', label: '', class: '', group: 'プラグイン' }] },
      status: 200,
      statusText: 'OK',
      headers: new Headers(),
    });

    const { getByTestId } = render(
      <BlockEditorSettingsProvider blockDefinitions={{ callout: calloutDef }}>
        <ContextConsumer />
      </BlockEditorSettingsProvider>,
      { wrapper }
    );

    await waitFor(() => {
      expect(getByTestId('block-menu-command-name').textContent).toBe('callout');
    });
  });
});
