import type { Meta, StoryObj } from '../../story.types';
import type { DataTableColumnDef } from '../data-table/types';
import { GridSelectElement } from './grid-select-element.component';

interface Client {
  id: string;
  name: string;
  email: string;
  segment: string;
}

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

const clients: Client[] = [
  { id: 'c1', name: 'Acme Corporation', email: 'hello@acme.com', segment: 'Enterprise' },
  { id: 'c2', name: 'Globex Industries', email: 'info@globex.com', segment: 'Mid-market' },
  { id: 'c3', name: 'Initech Technologies', email: 'contact@initech.com', segment: 'Enterprise' },
  { id: 'c4', name: 'Umbrella Labs', email: 'sales@umbrella.biz', segment: 'SMB' },
];

const columns: DataTableColumnDef<Client>[] = [
  {
    id: 'name',
    header: 'Name',
    accessorKey: 'name',
    size: 260,
  },
  {
    id: 'email',
    header: 'Email',
    accessorKey: 'email',
  },
  {
    id: 'segment',
    header: 'Segment',
    accessorKey: 'segment',
    size: 140,
  },
];

const meta: Meta<GridSelectElement<Client>> = {
  title: '@aurora/components/grid-select-element',
  component: GridSelectElement<Client>,
  tags: ['autodocs'],
  argTypes: {
    value: {
      control: 'text',
      description:
        'Currently selected entity id. `null` means no selection. Host keeps `value` and `options` consistent — if the selected id is not in `options`, the trigger falls back to `placeholder`.',
    },
    options: {
      control: 'object',
      description:
        'Entities to render as rows. Typically loaded by the host via `useGraphqlPaginate` + `useGraphqlGet` and paginated server-side through `searchChange`.',
    },
    columns: {
      control: 'object',
      description:
        '`DataTableColumnDef<T>[]` shared with the list view of the same entity. Headers and cells render via TanStack FlexRender — custom cell components are supported.',
    },
    placeholder: {
      control: 'text',
      description:
        'Trigger label when nothing is selected. Also used as dialog title when `dialogTitle` is empty.',
    },
    dialogTitle: {
      control: 'text',
      description: 'Title of the dialog header. Defaults to `placeholder` when empty.',
    },
    loading: {
      control: 'boolean',
      description: 'Renders a spinner inside the table body while the host is fetching.',
    },
    disabled: {
      control: 'boolean',
      description: 'Disables the trigger button. The dialog cannot be opened while disabled.',
    },
    searchPlaceholder: {
      control: 'text',
      description: 'Placeholder shown inside the internal search box (`au-table-search`).',
    },
    emptyMessage: {
      control: 'text',
      description: 'Text shown in a single-row cell when `options` is empty and not loading.',
    },
    displayWith: {
      control: false,
      description:
        'Function that renders the trigger label for the selected entity. Defaults to `entity.id`. Override to show a human-readable representation.',
    },
    valueChange: {
      action: 'valueChange',
      description:
        'Emits the newly selected entity id (via `row.id`). The component closes the dialog after emitting.',
    },
    searchChange: {
      action: 'searchChange',
      description:
        'Emits the debounced search string from the internal `au-table-search`. The host reacts by loading a filtered page of `options`.',
    },
  },
  args: {
    value: null,
    options: clients,
    columns,
    placeholder: 'Select client',
    dialogTitle: 'Pick a client',
    loading: false,
    disabled: false,
    searchPlaceholder: 'Filter clients...',
    emptyMessage: 'No clients found',
    displayWith: (c: Client) => c.name,
  },
  parameters: {
    aurora: {
      category: 'form',
      when: 'Many-to-one relationship picker rendered as a modal table. Use when the consumer wants multiple columns of context to disambiguate the choice (e.g., name + email + segment). Runtime target of the YAML `webComponent.type: grid-select-element`.',
      whenNot:
        'For a typable dropdown with server-side search, use `AsyncSearchSelect` (simpler interaction, no dialog). For many-to-many pick, use `GridSelectMultipleElements`. For nested CRUD of child entities, use `GridElementsManagerComponent`.',
    },
  },
};

export default meta;

export const Default: Story = {};

export const WithPreselected: Story = {
  name: 'With preselected value',
  args: {
    value: 'c3',
  },
  parameters: {
    docs: {
      description: {
        story:
          'Trigger renders the label of the pre-selected entity via `displayWith`. Typical edit mode. If the selected id is missing from `options`, the trigger falls back to `placeholder` until the host injects the option.',
      },
    },
  },
};

export const Loading: Story = {
  args: {
    loading: true,
    options: [],
  },
  parameters: {
    docs: {
      description: {
        story:
          'Loading state inside the dialog body — a spinner replaces rows while the host fetches options. The trigger button remains interactive (the user can still open/close the dialog).',
      },
    },
  },
};

export const Empty: Story = {
  args: {
    options: [],
    emptyMessage: 'No results — try a different search',
  },
  parameters: {
    docs: {
      description: {
        story:
          'Empty state inside the dialog. The host controls the message text; the component only renders the string it receives.',
      },
    },
  },
};

export const Disabled: Story = {
  args: {
    disabled: true,
    placeholder: 'Disabled',
  },
  parameters: {
    docs: {
      description: {
        story:
          'Disabled state prevents the dialog from opening. The button receives the native `disabled` attribute; clicks are swallowed by the browser.',
      },
    },
  },
};

export const CustomCells: Story = {
  name: 'With custom cell (badge segment)',
  args: {
    columns: [
      ...columns.slice(0, 2),
      {
        id: 'segment',
        header: 'Segment',
        size: 140,
        cell: (ctx) => {
          const value = ctx.row.original.segment;
          return `<span class="inline-flex rounded-md bg-accent px-2 py-0.5 text-xs font-medium">${value}</span>`;
        },
      },
    ] as DataTableColumnDef<Client>[],
  },
  parameters: {
    docs: {
      description: {
        story:
          'TanStack `columnDef.cell` accepts a function that returns a string. The component renders the returned HTML via `[innerHTML]` inside FlexRender — same pattern as `aurora-data-table`. For component-based cells use `flexRenderComponent` (see `tag-list.component.ts`).',
      },
    },
  },
};
