import type { Meta, StoryObj } from '../../story.types';
import type { DataTableColumnDef, DataTableData } from '../data-table/types';
import { GridPickDialog } from './grid-pick-dialog.component';

interface Permission {
  id: string;
  name: string;
  scope: string;
}

// biome-ignore lint/suspicious/noExplicitAny: Story type must be concrete to be rendered by CSF tooling
type Story = StoryObj<GridPickDialog<any>>;

const PERMISSIONS: Permission[] = [
  { id: 'p1', name: 'iam.read', scope: 'Iam' },
  { id: 'p2', name: 'iam.write', scope: 'Iam' },
  { id: 'p3', name: 'iam.delete', scope: 'Iam' },
  { id: 'p4', name: 'sales.read', scope: 'Sales' },
  { id: 'p5', name: 'sales.write', scope: 'Sales' },
];

const COLUMNS: DataTableColumnDef<Permission>[] = [
  { id: 'name', header: 'Name', accessorKey: 'name', size: 240 },
  { id: 'scope', header: 'Scope', accessorKey: 'scope', size: 140 },
];

const FULL_PAGE: DataTableData<Permission> = {
  count: PERMISSIONS.length,
  total: PERMISSIONS.length,
  rows: PERMISSIONS,
};

const meta: Meta<GridPickDialog<Permission>> = {
  title: '@aurora/components/grid-pick-dialog',
  component: GridPickDialog<Permission>,
  tags: ['autodocs'],
  argTypes: {
    data: {
      control: 'object',
      description:
        'Server-paginated `DataTableData<T>` for the candidate rows. Host fetches in response to `stateChange` and feeds it back here.',
    },
    columns: {
      control: 'object',
      description:
        '`DataTableColumnDef<T>[]` to render after the prepended selection column (when `multi=true`).',
    },
    disabledIds: {
      control: 'object',
      description:
        'Set of entity ids to render with a done-icon instead of the selection control. The dialog ignores click/toggle on those rows.',
    },
    multi: {
      control: 'boolean',
      description:
        '`true` (default) shows checkbox selection + Apply/Cancel footer. `false` triggers immediate `linkRequested([id])` + `closed` on row click — no selection column.',
    },
    open: {
      control: 'boolean',
      description:
        'Controlled state — host opens/closes via this input. When transitioning to `false`, the selection and search reset so the next open starts clean.',
    },
    title: { control: 'text' },
    applyLabel: { control: 'text' },
    cancelLabel: { control: 'text' },
    searchPlaceholder: { control: 'text' },
    emptyMessage: { control: 'text' },
    disabledRowTooltip: { control: 'text' },
    loading: { control: 'boolean' },
    stateChange: {
      action: 'stateChange',
      description:
        'Emits aggregated `ServerTableState` on every sort/page/search change. Host fetches and updates `data` in response.',
    },
    linkRequested: {
      action: 'linkRequested',
      description:
        '`multi=true` → emits selected id array on Apply (selection persists across page/sort/search — IDs not currently visible may be in the array). `multi=false` → emits `[id]` immediately on row click.',
    },
    closed: {
      action: 'closed',
      description:
        'Emits when the dialog closes (Apply, Cancel, or backdrop). Host reflects to `open`.',
    },
  },
  args: {
    data: FULL_PAGE,
    columns: COLUMNS,
    disabledIds: new Set<string>(),
    multi: true,
    open: true,
    title: 'Pick permissions',
    applyLabel: 'Add selected',
    cancelLabel: 'Cancel',
    searchPlaceholder: 'Filter permissions...',
    emptyMessage: 'No permissions found',
    disabledRowTooltip: 'Already linked',
    loading: false,
  },
  parameters: {
    aurora: {
      category: 'form',
      when: 'Reusable picker dialog with server-paginated table inside HlmDialog. Used internally by `grid-select-multiple-elements` (multi-select many-to-many) and intended for future reuse by `grid-select-element` (single-pick many-to-one).',
      whenNot:
        'For a select-style trigger inline in a form, use `search-select` / `multiple-search-select` / `async-search-select`. For a full manager (linked table + this dialog) use `grid-select-multiple-elements`.',
    },
  },
};

export default meta;

export const Default: Story = {};

export const Empty: Story = {
  args: {
    data: { count: 0, total: 0, rows: [] },
    emptyMessage: 'No candidates available',
  },
  parameters: {
    docs: {
      description: { story: 'Empty state when the candidate list has no rows.' },
    },
  },
};

export const Loading: Story = {
  args: {
    loading: true,
    data: { count: 0, total: 0, rows: [] },
  },
  parameters: {
    docs: {
      description: {
        story: 'Loading state shown inside the table body while the host fetches a page.',
      },
    },
  },
};

export const WithDisabledIds: Story = {
  name: 'With disabled (already linked) ids',
  args: {
    disabledIds: new Set(['p1', 'p3']),
  },
  parameters: {
    docs: {
      description: {
        story:
          'Rows with id in `disabledIds` render a done-icon instead of the checkbox. Apply emits only the user-selected ids — disabled ids never enter the selection.',
      },
    },
  },
};

export const MultipleSelection: Story = {
  name: 'Multiple selection (multi=true)',
  args: { multi: true },
  parameters: {
    docs: {
      description: {
        story:
          'Default many-to-many mode. Selection persists across paginate/sort/search — IDs ticked on a previous page remain in the internal Set even if the current `data.rows` does not contain them.',
      },
    },
  },
};

export const SingleSelection: Story = {
  name: 'Single selection (multi=false)',
  args: {
    multi: false,
    title: 'Pick one permission',
  },
  parameters: {
    docs: {
      description: {
        story:
          'many-to-one mode. The selection column is hidden. Clicking a non-disabled row immediately emits `linkRequested([id])` and `closed` — no Apply button. Disabled rows ignore the click.',
      },
    },
  },
};
