import { describe, expect, it, beforeEach, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { CellContext } from '@tanstack/react-table';
import { DataView } from '@ablogcms/components/dataview';
import type { AccessorColumn, BulkAction, Column, PaginationInfo, View } from '@ablogcms/components/dataview/types';
import { ENTRY_COLUMNS } from './index';
import type { EntryType } from '../types';

// CMS-7840: タイトルが長いエントリーで一覧行が横に長くなる問題の特徴付けテスト。
// title列は省略表示（ellipsis）し、ホバー時にツールチップ（data-tooltip-content）で全文を見せる。
function createTitleCellContext(entry: Pick<EntryType, 'id' | 'url' | 'title'>) {
  return {
    getValue: () => entry.title,
    row: { original: entry },
  } as unknown as CellContext<EntryType, EntryType['title']>;
}

describe('ENTRY_COLUMNS の title 列', () => {
  const titleColumn = ENTRY_COLUMNS.find((column) => column.id === 'title') as AccessorColumn<EntryType>;

  beforeEach(() => {
    window.ACMS.Config = {
      ...window.ACMS.Config,
      entryAdminConfig: { titleMaxLength: 10 },
    };
  });

  it('タイトルが最大文字数以下の場合はそのまま表示し、リンク先はエントリーのURLになる', () => {
    const info = createTitleCellContext({ id: 1, url: '/entry/1/', title: '短いタイトル' });

    render(<>{titleColumn.getValue?.(info)}</>);

    const link = screen.getByRole('link', { name: '短いタイトル' });
    expect(link).toHaveAttribute('href', '/entry/1/');
  });

  it('タイトルが最大文字数を超える場合は省略表示し、ツールチップ用属性に全文を保持する', () => {
    const longTitle = 'とても長いタイトルの一例テキストです';
    const info = createTitleCellContext({ id: 2, url: '/entry/2/', title: longTitle });

    render(<>{titleColumn.getValue?.(info)}</>);

    const link = screen.getByRole('link');
    expect(link.textContent).not.toBe(longTitle);
    expect(link.textContent?.endsWith('...')).toBe(true);
    expect(link).toHaveAttribute('data-tooltip-content', longTitle);
  });
});

// 表示順カラムは行内に描画されるが、送信先は DataView が描画する一括操作フォームであり、
// form 属性による関連付けだけが両者を繋いでいる。id をリテラルで書くと実在しない id を指しても
// 型・Lint では検出できず、sort-{eid} が FormData から静かに脱落して
// サーバー側のフォールバックで表示順が 1 で上書きされる。その経路を丸ごと固定する。
const view: View = { type: 'table', pageSize: 10 };
const paginationInfo: PaginationInfo = { totalItems: 1, pageSizes: [10] };
const entry = { id: 623, sort: 1 } as EntryType;
const sortColumn = ENTRY_COLUMNS.find((column) => column.id === 'sort') as unknown as Column<EntryType>;

describe('ENTRY_COLUMNS sort column', () => {
  it('submits the entered sort value as sort-{entryId} through the bulk action form', async () => {
    const user = userEvent.setup();
    const onAction = vi.fn();
    const bulkActions: BulkAction<EntryType>[] = [
      {
        id: 'order',
        label: 'entry_index.bulk_action.order',
        onAction,
        renderForm: () => (
          <button type="submit" name="intent" value="category">
            entry_index.bulk_change
          </button>
        ),
      },
    ];

    render(
      <DataView<EntryType>
        view={view}
        onViewChange={() => {}}
        data={[entry]}
        columns={[sortColumn]}
        paginationInfo={paginationInfo}
        bulkActions={bulkActions}
        enableRowSelection
        getRowId={(row) => `2:${row.id}`}
      />
    );

    const sortInput = screen.getByLabelText('entry_index.sort');
    await user.clear(sortInput);
    await user.type(sortInput, '3');
    await user.click(screen.getByLabelText('dataview.select_rows'));
    await user.selectOptions(screen.getByLabelText('dataview.bulk_actions'), 'order');
    await user.click(screen.getByRole('button', { name: 'entry_index.bulk_change' }));

    expect(onAction).toHaveBeenCalledTimes(1);
    const formData = onAction.mock.calls[0][0] as FormData;
    expect(formData.getAll('checks[]')).toEqual(['2:623']);
    expect(formData.get('sort-623')).toBe('3');
  });
});
