import type { Meta, StoryObj } from '@storybook/react-webpack5';
import {
  expect,
  fireEvent,
  fn,
  type Mock,
  screen,
  userEvent,
  waitFor,
  within,
} from 'storybook/test';
import { Flag } from '@wise/art';
import { useEffect, useRef, useState } from 'react';

import { allModes } from '../../../../.storybook/modes';
import { withVariantConfig } from '../../../../.storybook/helpers';
import Body from '../../../body';
import { Field } from '../../../field/Field';
import { lorem5, lorem500 } from '../../../test-utils';
import { sortByRelevance } from '../SelectInput.utils';
import {
  SelectInput,
  type SelectInputItem,
  SelectInputOptionContent,
  type SelectInputProps,
} from '..';

const meta = {
  title: 'Forms/SelectInput/Tests',
  component: SelectInput,
  args: {
    onFilterChange: fn() satisfies Mock,
    onChange: fn() satisfies Mock,
    onClose: fn() satisfies Mock,
    onOpen: fn() satisfies Mock,
  },
  tags: ['!autodocs', '!manifest'],
} satisfies Meta<typeof SelectInput>;
export default meta;

type Story<T, M extends boolean = false> = StoryObj<SelectInputProps<T, M>>;

interface TestMonth {
  id: number;
  name: string;
}

const testMonths: TestMonth[] = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December',
].map((name, index) => ({ id: index + 1, name }));

interface TestCurrency {
  code: string;
  name: string;
  countries?: string[];
}

const testPopularCurrencies: TestCurrency[] = [
  { code: 'USD', name: 'United States Dollar', countries: ['Hong Kong', 'Saudi Arabia'] },
  { code: 'EUR', name: 'Euro', countries: ['Spain', 'Germany', 'France', 'Austria', 'Estonia'] },
  { code: 'GBP', name: 'British pound', countries: ['England', 'Scotland', 'Wales'] },
];

const testAllCurrencies: TestCurrency[] = [
  ...testPopularCurrencies,
  { code: 'AUD', name: 'Australian dollar' },
  { code: 'CAD', name: 'Canadian dollar', countries: ['Canada'] },
  { code: 'ÅLD', name: 'Ålandian peso', countries: ['Ålandia'] },
].sort((a, b) => a.code.localeCompare(b.code));

function testCurrencyOption(currency: TestCurrency) {
  return {
    type: 'option',
    value: currency,
    filterMatchers: [currency.code, currency.name, ...(currency.countries ?? [])],
  } satisfies SelectInputItem<TestCurrency>;
}

/**
 * Visual regression story: all three sizes rendered across every theme.
 * - `sm` — opened, simple (months) list
 * - `md` — closed
 * - `lg` — opened, grouped currencies list
 */
export const Variants: Story<TestCurrency> = {
  render: function Render() {
    const smRef = useRef<HTMLButtonElement | null>(null);
    const lgRef = useRef<HTMLButtonElement | null>(null);

    const simpleItems: SelectInputItem<TestMonth>[] = testMonths.map((month) => ({
      type: 'option',
      value: month,
    }));

    const groupedItems: SelectInputItem<TestCurrency>[] = [
      {
        type: 'group',
        label: 'Popular currencies',
        options: testPopularCurrencies.map(testCurrencyOption),
      },
      {
        type: 'group',
        label: 'All currencies',
        options: testAllCurrencies.map(testCurrencyOption),
      },
    ];

    useEffect(() => {
      const timer = setTimeout(() => {
        smRef.current?.click();
        setTimeout(() => {
          lgRef.current?.click();
        }, 100);
      }, 200);
      return () => clearTimeout(timer);
    }, []);

    return (
      <div style={{ display: 'flex', gap: '2rem' }}>
        <div style={{ minHeight: '550px', width: '280px' }}>
          <p className="np-text-body-small m-b-1">Small (opened)</p>
          <SelectInput<TestMonth>
            size="sm"
            placeholder="Month"
            items={simpleItems}
            triggerRef={smRef}
            renderValue={(month) => <SelectInputOptionContent title={month.name} />}
          />
        </div>
        <div style={{ width: '280px' }}>
          <p className="np-text-body-small m-b-1">Medium</p>
          <SelectInput<TestMonth>
            size="md"
            placeholder="Month"
            items={simpleItems}
            renderValue={(month) => <SelectInputOptionContent title={month.name} />}
          />
        </div>
        <div style={{ minHeight: '550px', width: '280px' }}>
          <p className="np-text-body-small m-b-1">Large (opened)</p>
          <SelectInput<TestCurrency>
            size="lg"
            placeholder="Currency"
            items={groupedItems}
            triggerRef={lgRef}
            renderValue={(currency) => (
              <SelectInputOptionContent
                title={currency.code}
                note={currency.name}
                icon={<Flag code={currency.code} intrinsicSize={24} />}
              />
            )}
          />
        </div>
      </div>
    );
  },
  ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green', 'rtl']),
};

/**
 * Test story with a large list of countries where almost all have "United States dollar"
 * in their metadata. This reproduces the bug where searching "united" would scroll to
 * the bottom of the list instead of staying at the top.
 * https://transferwise.atlassian.net/browse/DS-8048
 */
export const VirtualizedCountryListTest: Story<{ title: string; value: string }> = {
  args: {
    items: [
      // Popular countries group - all have USD in metadata
      {
        type: 'group',
        label: 'Popular countries',
        options: [
          {
            type: 'option',
            value: { title: 'United States', value: 'US' },
            filterMatchers: ['United States', 'USA', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'United Kingdom', value: 'GB' },
            filterMatchers: [
              'United Kingdom',
              'UK',
              'British pound',
              'GBP',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Germany', value: 'DE' },
            filterMatchers: [
              'Germany',
              'Deutschland',
              'Euro',
              'EUR',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'France', value: 'FR' },
            filterMatchers: ['France', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
        ],
      },
      // All countries group - massive list with USD in most
      {
        type: 'group',
        label: 'All countries',
        options: [
          {
            type: 'option',
            value: { title: 'Afghanistan', value: 'AF' },
            filterMatchers: ['Afghanistan', 'Afghan afghani', 'AFN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Albania', value: 'AL' },
            filterMatchers: ['Albania', 'Albanian lek', 'ALL', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Algeria', value: 'DZ' },
            filterMatchers: ['Algeria', 'Algerian dinar', 'DZD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Andorra', value: 'AD' },
            filterMatchers: ['Andorra', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Angola', value: 'AO' },
            filterMatchers: ['Angola', 'Angolan kwanza', 'AOA', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Argentina', value: 'AR' },
            filterMatchers: ['Argentina', 'Argentine peso', 'ARS', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Armenia', value: 'AM' },
            filterMatchers: ['Armenia', 'Armenian dram', 'AMD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Australia', value: 'AU' },
            filterMatchers: [
              'Australia',
              'Australian dollar',
              'AUD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Austria', value: 'AT' },
            filterMatchers: ['Austria', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Azerbaijan', value: 'AZ' },
            filterMatchers: [
              'Azerbaijan',
              'Azerbaijani manat',
              'AZN',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Bahamas', value: 'BS' },
            filterMatchers: ['Bahamas', 'Bahamian dollar', 'BSD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Bahrain', value: 'BH' },
            filterMatchers: ['Bahrain', 'Bahraini dinar', 'BHD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Bangladesh', value: 'BD' },
            filterMatchers: [
              'Bangladesh',
              'Bangladeshi taka',
              'BDT',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Barbados', value: 'BB' },
            filterMatchers: ['Barbados', 'Barbadian dollar', 'BBD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Belarus', value: 'BY' },
            filterMatchers: ['Belarus', 'Belarusian ruble', 'BYN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Belgium', value: 'BE' },
            filterMatchers: ['Belgium', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Belize', value: 'BZ' },
            filterMatchers: ['Belize', 'Belize dollar', 'BZD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Benin', value: 'BJ' },
            filterMatchers: [
              'Benin',
              'West African CFA franc',
              'XOF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Bhutan', value: 'BT' },
            filterMatchers: ['Bhutan', 'Bhutanese ngultrum', 'BTN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Bolivia', value: 'BO' },
            filterMatchers: ['Bolivia', 'Bolivian boliviano', 'BOB', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Bosnia and Herzegovina', value: 'BA' },
            filterMatchers: [
              'Bosnia',
              'Herzegovina',
              'Convertible mark',
              'BAM',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Botswana', value: 'BW' },
            filterMatchers: ['Botswana', 'Botswana pula', 'BWP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Brazil', value: 'BR' },
            filterMatchers: ['Brazil', 'Brazilian real', 'BRL', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Brunei', value: 'BN' },
            filterMatchers: ['Brunei', 'Brunei dollar', 'BND', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Bulgaria', value: 'BG' },
            filterMatchers: ['Bulgaria', 'Bulgarian lev', 'BGN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Burkina Faso', value: 'BF' },
            filterMatchers: [
              'Burkina Faso',
              'West African CFA franc',
              'XOF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Burundi', value: 'BI' },
            filterMatchers: ['Burundi', 'Burundian franc', 'BIF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Cambodia', value: 'KH' },
            filterMatchers: ['Cambodia', 'Cambodian riel', 'KHR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Cameroon', value: 'CM' },
            filterMatchers: [
              'Cameroon',
              'Central African CFA franc',
              'XAF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Canada', value: 'CA' },
            filterMatchers: ['Canada', 'Canadian dollar', 'CAD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Cape Verde', value: 'CV' },
            filterMatchers: [
              'Cape Verde',
              'Cape Verdean escudo',
              'CVE',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Central African Republic', value: 'CF' },
            filterMatchers: [
              'Central African Republic',
              'Central African CFA franc',
              'XAF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Chad', value: 'TD' },
            filterMatchers: [
              'Chad',
              'Central African CFA franc',
              'XAF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Chile', value: 'CL' },
            filterMatchers: ['Chile', 'Chilean peso', 'CLP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'China', value: 'CN' },
            filterMatchers: ['China', 'Chinese yuan', 'CNY', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Colombia', value: 'CO' },
            filterMatchers: ['Colombia', 'Colombian peso', 'COP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Comoros', value: 'KM' },
            filterMatchers: ['Comoros', 'Comorian franc', 'KMF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Congo', value: 'CG' },
            filterMatchers: [
              'Congo',
              'Central African CFA franc',
              'XAF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Costa Rica', value: 'CR' },
            filterMatchers: [
              'Costa Rica',
              'Costa Rican colón',
              'CRC',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Croatia', value: 'HR' },
            filterMatchers: ['Croatia', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Cuba', value: 'CU' },
            filterMatchers: ['Cuba', 'Cuban peso', 'CUP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Cyprus', value: 'CY' },
            filterMatchers: ['Cyprus', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Czech Republic', value: 'CZ' },
            filterMatchers: [
              'Czech Republic',
              'Czech koruna',
              'CZK',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Denmark', value: 'DK' },
            filterMatchers: ['Denmark', 'Danish krone', 'DKK', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Djibouti', value: 'DJ' },
            filterMatchers: ['Djibouti', 'Djiboutian franc', 'DJF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Dominica', value: 'DM' },
            filterMatchers: [
              'Dominica',
              'East Caribbean dollar',
              'XCD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Dominican Republic', value: 'DO' },
            filterMatchers: [
              'Dominican Republic',
              'Dominican peso',
              'DOP',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Ecuador', value: 'EC' },
            filterMatchers: ['Ecuador', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Egypt', value: 'EG' },
            filterMatchers: ['Egypt', 'Egyptian pound', 'EGP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'El Salvador', value: 'SV' },
            filterMatchers: ['El Salvador', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Equatorial Guinea', value: 'GQ' },
            filterMatchers: [
              'Equatorial Guinea',
              'Central African CFA franc',
              'XAF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Eritrea', value: 'ER' },
            filterMatchers: ['Eritrea', 'Eritrean nakfa', 'ERN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Estonia', value: 'EE' },
            filterMatchers: ['Estonia', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Ethiopia', value: 'ET' },
            filterMatchers: ['Ethiopia', 'Ethiopian birr', 'ETB', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Fiji', value: 'FJ' },
            filterMatchers: ['Fiji', 'Fijian dollar', 'FJD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Finland', value: 'FI' },
            filterMatchers: ['Finland', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Gabon', value: 'GA' },
            filterMatchers: [
              'Gabon',
              'Central African CFA franc',
              'XAF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Gambia', value: 'GM' },
            filterMatchers: ['Gambia', 'Gambian dalasi', 'GMD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Georgia', value: 'GE' },
            filterMatchers: ['Georgia', 'Georgian lari', 'GEL', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Ghana', value: 'GH' },
            filterMatchers: ['Ghana', 'Ghanaian cedi', 'GHS', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Greece', value: 'GR' },
            filterMatchers: ['Greece', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Grenada', value: 'GD' },
            filterMatchers: [
              'Grenada',
              'East Caribbean dollar',
              'XCD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Guatemala', value: 'GT' },
            filterMatchers: [
              'Guatemala',
              'Guatemalan quetzal',
              'GTQ',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Guinea', value: 'GN' },
            filterMatchers: ['Guinea', 'Guinean franc', 'GNF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Guinea-Bissau', value: 'GW' },
            filterMatchers: [
              'Guinea-Bissau',
              'West African CFA franc',
              'XOF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Guyana', value: 'GY' },
            filterMatchers: ['Guyana', 'Guyanese dollar', 'GYD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Haiti', value: 'HT' },
            filterMatchers: ['Haiti', 'Haitian gourde', 'HTG', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Honduras', value: 'HN' },
            filterMatchers: ['Honduras', 'Honduran lempira', 'HNL', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Hungary', value: 'HU' },
            filterMatchers: ['Hungary', 'Hungarian forint', 'HUF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Iceland', value: 'IS' },
            filterMatchers: ['Iceland', 'Icelandic króna', 'ISK', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'India', value: 'IN' },
            filterMatchers: ['India', 'Indian rupee', 'INR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Indonesia', value: 'ID' },
            filterMatchers: [
              'Indonesia',
              'Indonesian rupiah',
              'IDR',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Iran', value: 'IR' },
            filterMatchers: ['Iran', 'Iranian rial', 'IRR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Iraq', value: 'IQ' },
            filterMatchers: ['Iraq', 'Iraqi dinar', 'IQD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Ireland', value: 'IE' },
            filterMatchers: ['Ireland', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Israel', value: 'IL' },
            filterMatchers: ['Israel', 'Israeli new shekel', 'ILS', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Italy', value: 'IT' },
            filterMatchers: ['Italy', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Jamaica', value: 'JM' },
            filterMatchers: ['Jamaica', 'Jamaican dollar', 'JMD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Japan', value: 'JP' },
            filterMatchers: ['Japan', 'Japanese yen', 'JPY', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Jordan', value: 'JO' },
            filterMatchers: ['Jordan', 'Jordanian dinar', 'JOD', 'United States dollar', 'USD'],
          },
          // This one country does NOT have USD - to verify filtering works
          {
            type: 'option',
            value: { title: 'Kazakhstan', value: 'KZ' },
            filterMatchers: ['Kazakhstan', 'Kazakhstani tenge', 'KZT'],
          },
          {
            type: 'option',
            value: { title: 'Kenya', value: 'KE' },
            filterMatchers: ['Kenya', 'Kenyan shilling', 'KES', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Kiribati', value: 'KI' },
            filterMatchers: ['Kiribati', 'Australian dollar', 'AUD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Kuwait', value: 'KW' },
            filterMatchers: ['Kuwait', 'Kuwaiti dinar', 'KWD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Kyrgyzstan', value: 'KG' },
            filterMatchers: ['Kyrgyzstan', 'Kyrgyzstani som', 'KGS', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Laos', value: 'LA' },
            filterMatchers: ['Laos', 'Lao kip', 'LAK', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Latvia', value: 'LV' },
            filterMatchers: ['Latvia', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Lebanon', value: 'LB' },
            filterMatchers: ['Lebanon', 'Lebanese pound', 'LBP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Lesotho', value: 'LS' },
            filterMatchers: ['Lesotho', 'Lesotho loti', 'LSL', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Liberia', value: 'LR' },
            filterMatchers: ['Liberia', 'Liberian dollar', 'LRD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Libya', value: 'LY' },
            filterMatchers: ['Libya', 'Libyan dinar', 'LYD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Liechtenstein', value: 'LI' },
            filterMatchers: ['Liechtenstein', 'Swiss franc', 'CHF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Lithuania', value: 'LT' },
            filterMatchers: ['Lithuania', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Luxembourg', value: 'LU' },
            filterMatchers: ['Luxembourg', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Madagascar', value: 'MG' },
            filterMatchers: ['Madagascar', 'Malagasy ariary', 'MGA', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Malawi', value: 'MW' },
            filterMatchers: ['Malawi', 'Malawian kwacha', 'MWK', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Malaysia', value: 'MY' },
            filterMatchers: ['Malaysia', 'Malaysian ringgit', 'MYR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Maldives', value: 'MV' },
            filterMatchers: ['Maldives', 'Maldivian rufiyaa', 'MVR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Mali', value: 'ML' },
            filterMatchers: [
              'Mali',
              'West African CFA franc',
              'XOF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Malta', value: 'MT' },
            filterMatchers: ['Malta', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Marshall Islands', value: 'MH' },
            filterMatchers: ['Marshall Islands', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Mauritania', value: 'MR' },
            filterMatchers: [
              'Mauritania',
              'Mauritanian ouguiya',
              'MRU',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Mauritius', value: 'MU' },
            filterMatchers: ['Mauritius', 'Mauritian rupee', 'MUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Mexico', value: 'MX' },
            filterMatchers: ['Mexico', 'Mexican peso', 'MXN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Micronesia', value: 'FM' },
            filterMatchers: ['Micronesia', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Moldova', value: 'MD' },
            filterMatchers: ['Moldova', 'Moldovan leu', 'MDL', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Monaco', value: 'MC' },
            filterMatchers: ['Monaco', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Mongolia', value: 'MN' },
            filterMatchers: ['Mongolia', 'Mongolian tögrög', 'MNT', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Montenegro', value: 'ME' },
            filterMatchers: ['Montenegro', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Morocco', value: 'MA' },
            filterMatchers: ['Morocco', 'Moroccan dirham', 'MAD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Mozambique', value: 'MZ' },
            filterMatchers: [
              'Mozambique',
              'Mozambican metical',
              'MZN',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Myanmar', value: 'MM' },
            filterMatchers: ['Myanmar', 'Burmese kyat', 'MMK', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Namibia', value: 'NA' },
            filterMatchers: ['Namibia', 'Namibian dollar', 'NAD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Nauru', value: 'NR' },
            filterMatchers: ['Nauru', 'Australian dollar', 'AUD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Nepal', value: 'NP' },
            filterMatchers: ['Nepal', 'Nepalese rupee', 'NPR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Netherlands', value: 'NL' },
            filterMatchers: ['Netherlands', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'New Zealand', value: 'NZ' },
            filterMatchers: [
              'New Zealand',
              'New Zealand dollar',
              'NZD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Nicaragua', value: 'NI' },
            filterMatchers: [
              'Nicaragua',
              'Nicaraguan córdoba',
              'NIO',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Niger', value: 'NE' },
            filterMatchers: [
              'Niger',
              'West African CFA franc',
              'XOF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Nigeria', value: 'NG' },
            filterMatchers: ['Nigeria', 'Nigerian naira', 'NGN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'North Macedonia', value: 'MK' },
            filterMatchers: [
              'North Macedonia',
              'Macedonian denar',
              'MKD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Norway', value: 'NO' },
            filterMatchers: ['Norway', 'Norwegian krone', 'NOK', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Oman', value: 'OM' },
            filterMatchers: ['Oman', 'Omani rial', 'OMR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Pakistan', value: 'PK' },
            filterMatchers: ['Pakistan', 'Pakistani rupee', 'PKR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Palau', value: 'PW' },
            filterMatchers: ['Palau', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Panama', value: 'PA' },
            filterMatchers: ['Panama', 'Panamanian balboa', 'PAB', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Papua New Guinea', value: 'PG' },
            filterMatchers: [
              'Papua New Guinea',
              'Papua New Guinean kina',
              'PGK',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Paraguay', value: 'PY' },
            filterMatchers: [
              'Paraguay',
              'Paraguayan guaraní',
              'PYG',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Peru', value: 'PE' },
            filterMatchers: ['Peru', 'Peruvian sol', 'PEN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Philippines', value: 'PH' },
            filterMatchers: [
              'Philippines',
              'Philippine peso',
              'PHP',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Poland', value: 'PL' },
            filterMatchers: ['Poland', 'Polish złoty', 'PLN', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Portugal', value: 'PT' },
            filterMatchers: ['Portugal', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Qatar', value: 'QA' },
            filterMatchers: ['Qatar', 'Qatari riyal', 'QAR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Romania', value: 'RO' },
            filterMatchers: ['Romania', 'Romanian leu', 'RON', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Russia', value: 'RU' },
            filterMatchers: ['Russia', 'Russian ruble', 'RUB', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Rwanda', value: 'RW' },
            filterMatchers: ['Rwanda', 'Rwandan franc', 'RWF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Saint Lucia', value: 'LC' },
            filterMatchers: [
              'Saint Lucia',
              'East Caribbean dollar',
              'XCD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Samoa', value: 'WS' },
            filterMatchers: ['Samoa', 'Samoan tālā', 'WST', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'San Marino', value: 'SM' },
            filterMatchers: ['San Marino', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Saudi Arabia', value: 'SA' },
            filterMatchers: ['Saudi Arabia', 'Saudi riyal', 'SAR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Senegal', value: 'SN' },
            filterMatchers: [
              'Senegal',
              'West African CFA franc',
              'XOF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Serbia', value: 'RS' },
            filterMatchers: ['Serbia', 'Serbian dinar', 'RSD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Seychelles', value: 'SC' },
            filterMatchers: [
              'Seychelles',
              'Seychellois rupee',
              'SCR',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Sierra Leone', value: 'SL' },
            filterMatchers: [
              'Sierra Leone',
              'Sierra Leonean leone',
              'SLL',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Singapore', value: 'SG' },
            filterMatchers: ['Singapore', 'Singapore dollar', 'SGD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Slovakia', value: 'SK' },
            filterMatchers: ['Slovakia', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Slovenia', value: 'SI' },
            filterMatchers: ['Slovenia', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Solomon Islands', value: 'SB' },
            filterMatchers: [
              'Solomon Islands',
              'Solomon Islands dollar',
              'SBD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Somalia', value: 'SO' },
            filterMatchers: ['Somalia', 'Somali shilling', 'SOS', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'South Africa', value: 'ZA' },
            filterMatchers: [
              'South Africa',
              'South African rand',
              'ZAR',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'South Korea', value: 'KR' },
            filterMatchers: ['South Korea', 'Korean won', 'KRW', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'South Sudan', value: 'SS' },
            filterMatchers: [
              'South Sudan',
              'South Sudanese pound',
              'SSP',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Spain', value: 'ES' },
            filterMatchers: ['Spain', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Sri Lanka', value: 'LK' },
            filterMatchers: ['Sri Lanka', 'Sri Lankan rupee', 'LKR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Sudan', value: 'SD' },
            filterMatchers: ['Sudan', 'Sudanese pound', 'SDG', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Suriname', value: 'SR' },
            filterMatchers: ['Suriname', 'Surinamese dollar', 'SRD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Sweden', value: 'SE' },
            filterMatchers: ['Sweden', 'Swedish krona', 'SEK', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Switzerland', value: 'CH' },
            filterMatchers: ['Switzerland', 'Swiss franc', 'CHF', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Syria', value: 'SY' },
            filterMatchers: ['Syria', 'Syrian pound', 'SYP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Taiwan', value: 'TW' },
            filterMatchers: ['Taiwan', 'New Taiwan dollar', 'TWD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Tajikistan', value: 'TJ' },
            filterMatchers: [
              'Tajikistan',
              'Tajikistani somoni',
              'TJS',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Tanzania', value: 'TZ' },
            filterMatchers: [
              'Tanzania',
              'Tanzanian shilling',
              'TZS',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Thailand', value: 'TH' },
            filterMatchers: ['Thailand', 'Thai baht', 'THB', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Timor-Leste', value: 'TL' },
            filterMatchers: ['Timor-Leste', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Togo', value: 'TG' },
            filterMatchers: [
              'Togo',
              'West African CFA franc',
              'XOF',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Tonga', value: 'TO' },
            filterMatchers: ['Tonga', 'Tongan paʻanga', 'TOP', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Trinidad and Tobago', value: 'TT' },
            filterMatchers: [
              'Trinidad and Tobago',
              'Trinidad and Tobago dollar',
              'TTD',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Tunisia', value: 'TN' },
            filterMatchers: ['Tunisia', 'Tunisian dinar', 'TND', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Turkey', value: 'TR' },
            filterMatchers: ['Turkey', 'Turkish lira', 'TRY', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Turkmenistan', value: 'TM' },
            filterMatchers: [
              'Turkmenistan',
              'Turkmenistan manat',
              'TMT',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Tuvalu', value: 'TV' },
            filterMatchers: ['Tuvalu', 'Australian dollar', 'AUD', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Uganda', value: 'UG' },
            filterMatchers: ['Uganda', 'Ugandan shilling', 'UGX', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Ukraine', value: 'UA' },
            filterMatchers: ['Ukraine', 'Ukrainian hryvnia', 'UAH', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'United Arab Emirates', value: 'AE' },
            filterMatchers: [
              'United Arab Emirates',
              'UAE',
              'UAE dirham',
              'AED',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Uruguay', value: 'UY' },
            filterMatchers: ['Uruguay', 'Uruguayan peso', 'UYU', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Uzbekistan', value: 'UZ' },
            filterMatchers: [
              'Uzbekistan',
              'Uzbekistani soʻm',
              'UZS',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Vanuatu', value: 'VU' },
            filterMatchers: ['Vanuatu', 'Vanuatu vatu', 'VUV', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Vatican City', value: 'VA' },
            filterMatchers: ['Vatican City', 'Euro', 'EUR', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Venezuela', value: 'VE' },
            filterMatchers: [
              'Venezuela',
              'Venezuelan bolívar',
              'VES',
              'United States dollar',
              'USD',
            ],
          },
          {
            type: 'option',
            value: { title: 'Vietnam', value: 'VN' },
            filterMatchers: ['Vietnam', 'Vietnamese đồng', 'VND', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Yemen', value: 'YE' },
            filterMatchers: ['Yemen', 'Yemeni rial', 'YER', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Zambia', value: 'ZM' },
            filterMatchers: ['Zambia', 'Zambian kwacha', 'ZMW', 'United States dollar', 'USD'],
          },
          {
            type: 'option',
            value: { title: 'Zimbabwe', value: 'ZW' },
            filterMatchers: ['Zimbabwe', 'Zimbabwean dollar', 'ZWL', 'United States dollar', 'USD'],
          },
        ],
      },
    ],
    placeholder: 'Select a country',
    filterable: true,
    filterPlaceholder: 'Search countries...',
    sortFilteredOptions: sortByRelevance((value) => value.title),
    size: 'lg',
    renderValue: (value) => value.title,
    compareValues: (a, b) => a?.value === b?.value,
  } satisfies Story<{ title: string; value: string }>['args'],
  /**
   * Test steps:
   * 1. Open the dropdown
   * 2. Search for "united"
   * 3. Expected: List should stay at the top showing United States, United Kingdom, United Arab Emirates first
   * 4. Bug (if present): List would scroll to the bottom automatically
   *
   * Note: Kazakhstan is the only country without USD in metadata - searching for it should
   * show it's properly filtered out when searching "united".
   */
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const combobox = canvas.getByRole('combobox');
    await userEvent.click(combobox);
    const searchInput = screen.getByPlaceholderText('Search countries...');
    await userEvent.type(searchInput, 'united');
  },
};

const wait = async (duration = 500) =>
  new Promise<void>((resolve) => {
    setTimeout(resolve, duration);
  });

const currencyInteractionArgs = {
  items: [
    {
      type: 'group',
      label: 'Popular currencies',
      options: testPopularCurrencies.map(testCurrencyOption),
    },
    {
      type: 'group',
      label: 'All currencies',
      options: testAllCurrencies.map(testCurrencyOption),
    },
  ],
  defaultValue: testPopularCurrencies[0],
  renderValue: (currency: TestCurrency) => (
    <SelectInputOptionContent title={currency.code} note={currency.name} />
  ),
  renderFooter: ({
    resultsEmpty,
    queryNormalized,
  }: {
    resultsEmpty: boolean;
    queryNormalized: string | null | undefined;
  }) =>
    resultsEmpty && queryNormalized != null && /^[a-z]{3}$/u.test(queryNormalized) ? (
      <>
        It is not possible to use {queryNormalized.toUpperCase()} yet.{' '}
        <a href="#_" onClick={(e) => e.preventDefault()}>
          Email me when it is available.
        </a>
      </>
    ) : (
      <>
        Cannot find it?{' '}
        <a href="#_" onClick={(e) => e.preventDefault()}>
          Request the currency you need,
        </a>{' '}
        and we will notify you once it is available.
      </>
    ),
  filterable: true,
  filterPlaceholder: 'Type a currency / country',
  size: 'lg',
} satisfies Story<TestCurrency>['args'];

export const BasicInteraction: Story<TestMonth | null> = {
  args: {
    placeholder: 'Month',
    items: testMonths.map((month) => ({ type: 'option', value: month })),
    renderValue: (month) => <SelectInputOptionContent title={month.name} />,
  },
  render: function Render({ onChange, onClear, ...args }) {
    const [selectedMonth, setSelectedMonth] = useState<TestMonth | null>(null);
    return (
      <SelectInput
        {...args}
        value={selectedMonth}
        onChange={(month) => {
          setSelectedMonth(month);
          onChange?.(month);
        }}
        onClear={() => {
          setSelectedMonth(null);
          onClear?.();
        }}
      />
    );
  },
  play: async ({ canvasElement, step }) => {
    const canvas = within(canvasElement);

    await step('renders placeholder', async () => {
      const triggerButton = canvas.getByRole('combobox');
      await waitFor(async () => expect(triggerButton).toHaveTextContent('Month'));
    });

    await step('selects option via mouse', async () => {
      const triggerButton = canvas.getByRole('combobox');
      await userEvent.click(triggerButton);
      await userEvent.unhover(triggerButton);
      const option = within(screen.getByRole('listbox')).getByRole('option', { name: 'May' });
      await userEvent.click(option);
      await waitFor(async () => expect(triggerButton).toHaveTextContent('May'));
    });
  },
};

export const KeyboardInteraction: Story<TestCurrency> = {
  args: currencyInteractionArgs,
  play: async ({ step }) => {
    await step('Tab to the combobox', async () => {
      await userEvent.tab();
    });

    await step('Open the combobox', async () => {
      await userEvent.keyboard(' ');
    });

    await step('Check if options are displayed', async () => {
      await waitFor(async () => expect(await screen.findAllByRole('option')).toHaveLength(9));
      await waitFor(async () => expect(screen.getByText(/^Cannot find it\?/u)).toBeInTheDocument());
    });

    await step('Type "huf" in the combobox', async () => {
      // this is workaround for Chromatic: Firefox and Edge tests failing.
      // Unclear on a proper solution
      await wait(750);
      const input = await screen.findByRole('combobox');
      await userEvent.type(input, 'huf');
    });

    await step('Check if no options are displayed', async () => {
      // this is workaround for Chromatic: Firefox and Edge tests failing.
      // Unclear on a proper solution
      await wait(750);
      await expect(await screen.findByText(/^No results found/u)).toBeInTheDocument();
      await expect(
        await screen.findByText(/^It is not possible to use HUF yet\./u),
      ).toBeInTheDocument();
      await waitFor(
        async () => {
          await expect(screen.queryAllByRole('option')).toHaveLength(0);
        },
        { timeout: 1500 },
      );
    });

    await step('Remove last two characters', async () => {
      await wait(500);
      const input = await screen.findByRole('combobox');
      await userEvent.type(input, '{Backspace}{Backspace}');
    });

    await step('Check if two options are displayed', async () => {
      await waitFor(async () =>
        expect(within(screen.getByRole('listbox')).queryAllByRole('option')).toHaveLength(2),
      );
    });

    await step('Type "e" in the combobox', async () => {
      const input = await screen.findByRole('combobox');
      await userEvent.type(input, '{Backspace}e');
    });

    await step('Check if aria-activedescendant is set', async () => {
      const input = screen.getByRole('combobox');
      await waitFor(async () => expect(input).toHaveAttribute('aria-activedescendant'));
    });
  },
};

export const MultiSelectInteraction: Story<TestCurrency, true> = {
  args: {
    ...currencyInteractionArgs,
    multiple: true,
    placeholder: 'Choose currencies…',
    defaultValue: [testPopularCurrencies[0]],
    renderValue: (currency, withinTrigger) =>
      withinTrigger ? (
        currency.code
      ) : (
        <SelectInputOptionContent title={currency.code} note={currency.name} />
      ),
  },
  play: async ({ canvasElement, step, args }) => {
    const canvas = within(canvasElement);

    await step('Open the combobox', async () => {
      const triggerButton = canvas.getByRole('combobox');
      await userEvent.click(triggerButton);
      await wait(500);
      await userEvent.unhover(triggerButton);
      await expect(args.onOpen).toHaveBeenCalledOnce();
    });

    await step('Select EUR option', async () => {
      const option = within(screen.getByRole('listbox')).getAllByRole('option', {
        name: /^EUR/u,
      })[0];
      await wait(500);
      await userEvent.click(option);
    });

    await step('Check if selected options are displayed in trigger', async () => {
      const triggerButton = document.querySelector('button[role="combobox"]');
      await waitFor(async () => expect(triggerButton).toHaveTextContent('USD, EUR'));
    });
  },
};

/**
 * Verifies that currencies with non-ASCII characters (e.g. ÅLD / Ålandian peso)
 * render correctly in the dropdown and can be found via filter.
 */
export const SpecialCharacterOptions: Story<TestCurrency> = {
  args: {
    ...currencyInteractionArgs,
    filterable: true,
    filterPlaceholder: 'Type a currency',
  },
  play: async ({ canvasElement, step }) => {
    const canvas = within(canvasElement);

    await step('Open the combobox', async () => {
      const triggerButton = canvas.getByRole('combobox');
      await userEvent.click(triggerButton);
      await userEvent.unhover(triggerButton);
    });

    await step('ÅLD option is visible in dropdown', async () => {
      await waitFor(async () =>
        expect(
          within(screen.getByRole('listbox')).getByRole('option', { name: /ÅLD/u }),
        ).toBeInTheDocument(),
      );
    });

    await step('Filter for Ålandian peso', async () => {
      await wait(500);
      const input = await screen.findByRole('combobox');
      await userEvent.type(input, 'åla');
    });

    await step('Only ÅLD option remains', async () => {
      await waitFor(async () =>
        expect(within(screen.getByRole('listbox')).getAllByRole('option')).toHaveLength(1),
      );
    });
  },
};

export const WithClearInteraction: Story<TestCurrency> = {
  args: {
    ...currencyInteractionArgs,
    onClear: fn() satisfies Mock,
  },
  play: async ({ step }) => {
    await step('Has clear button', async () => {
      const clearBtn = await screen.findByRole('button', { name: 'Clear' });
      await expect(clearBtn).toBeInTheDocument();
    });
  },
};

/**
 * This test ensures that when the SelectInput is used within a scrollable page,
 * opening the dropdown does not cause any unwanted scrolling or layout shifts.
 * Expected preview should start with green bar at the top, with yellow section
 * not in the viewport. The issue is particularly prominent on iOS Safari.
 *
 * NB: This test is disabled in Chromatic as there's no obvious way to control
 * <html/> element of a snapshot. It's to be primarily used in manual testing
 * on an actual device or a simulator as it cannot be reproduced with mobile
 * emulation modes on desktop browsers.
 */
export const SmoothScrollReset: Story<string> = {
  args: {
    items: Array.from({ length: 15 }).map((_, id) => ({
      type: 'option',
      value: `option ${id + 1}`,
    })),
    placeholder: 'Select option',
  },
  decorators: [
    (Story) => (
      <>
        <style>{`html { scroll-behavior: smooth; }`}</style>
        <div>
          <div
            className="d-flex align-items-center justify-content-center"
            style={{
              backgroundColor: 'var(--color-bright-yellow)',
              height: 400,
            }}
          >
            This block should not be in the viewport.
          </div>
          <div style={{ height: 10, backgroundColor: 'var(--color-bright-green)' }} />
          <Field id="el1" label={lorem5}>
            <Story />
          </Field>
          <Body as="p">{lorem500}</Body>
        </div>
      </>
    ),
  ],
  play: async ({ canvasElement }) => {
    document.documentElement.scrollTop = 400;
    await wait();
    const canvas = within(canvasElement);
    // cannot use userEvent.click as it crashes on iOS Safari in the simulator
    await fireEvent.click(canvas.getByRole('combobox'));
  },
  globals: {
    viewport: { value: allModes.largeMobile.viewport, isRotated: false },
  },
  parameters: {
    chromatic: {
      disableSnapshot: true,
    },
  },
};

interface OptionWithDescription {
  id: string;
  title: string;
  description?: string;
}

const optionsWithDescription: OptionWithDescription[] = [
  { id: '1', title: 'Option One', description: 'This is the first option' },
  { id: '2', title: 'Option Two (no description)' },
  { id: '3', title: 'Option Three', description: 'This is the third option' },
];

/**
 * Test story to verify that SelectInput correctly displays an item with a description
 * when shown in the trigger button. The description should be visible in the trigger
 * after selection.
 */
export const TriggerWithDescription: Story<OptionWithDescription> = {
  args: {
    items: optionsWithDescription.map((option) => ({
      type: 'option',
      value: option,
    })),
    defaultValue: optionsWithDescription[0],
    placeholder: 'Select an option',
    renderValue: (option, withinTrigger) => (
      <SelectInputOptionContent
        title={option.title}
        description={withinTrigger ? option.description : undefined}
      />
    ),
  },
  render: function Render({ onChange, ...args }) {
    const [selectedOption, setSelectedOption] = useState<OptionWithDescription>(
      optionsWithDescription[0],
    );

    return (
      <SelectInput
        {...args}
        value={selectedOption}
        onChange={(option) => {
          setSelectedOption(option);
          onChange?.(option);
        }}
      />
    );
  },
};

/**
 * This test insures that there's no unintended page scroll after the dropdown
 * is closed without selecting an option (e.g. clicking outside).
 * It tests 2 scenarios:
 * 1. when the dropdown fits naturally on the screen below the trigger
 * 2. when there's not enough space below the trigger and it renders above it
 */
const generateNoScrollTest = (inverted?: boolean): Story<TestMonth | null> => ({
  render: function Render({ onChange, onClear, ...args }) {
    const [selectedMonth, setSelectedMonth] = useState<TestMonth | null>(null);

    return (
      <div>
        <style>
          {`
            .storybook-container{
              min-height: unset;
              height: unset;
            }
          `}
        </style>
        {inverted ? <p style={{ height: '70vh', background: 'blanchedalmond' }} /> : null}

        <SelectInput
          {...args}
          value={selectedMonth}
          onChange={(month) => {
            setSelectedMonth(month);
            onChange?.(month);
          }}
          onClear={() => {
            setSelectedMonth(null);
            onClear?.();
          }}
        />

        <p style={{ margin: '1rem 0', height: '150vh', background: 'blanchedalmond' }} />
      </div>
    );
  },
  args: {
    placeholder: 'Month',
    items: testMonths.map((month) => ({
      type: 'option',
      value: month,
    })),
    renderValue: (month) => <SelectInputOptionContent title={month.name} />,
  },
  play: async ({ canvasElement, step }) => {
    const canvas = within(canvasElement);
    const trigger = canvas.getByRole('combobox');

    await step('Open the combobox', async () => {
      await userEvent.click(trigger);
    });

    await step('Check if options are displayed', async () => {
      await waitFor(async () => expect(screen.queryAllByRole('option').length).toBeGreaterThan(0));
    });

    await step('Close the combobox', async () => {
      await userEvent.keyboard('{Escape}');
      await wait();
    });

    await step('Verify the page has not scrolled', async () => {
      const scrollParent = canvasElement.ownerDocument.documentElement;
      await expect(scrollParent.scrollTop).toBe(0);
    });
  },
});

export const NoScrollAfterCloseTop: Story<TestMonth | null> = {
  ...generateNoScrollTest(),
  ...withVariantConfig(['default']),
};

export const NoScrollAfterCloseBottom: Story<TestMonth | null> = {
  ...generateNoScrollTest(true),
  ...withVariantConfig(['default']),
};

/** Basic months dropdown at 400% zoom for accessibility testing. */
export const Zoom400: Story<TestMonth | null> = {
  render: function Render({ onChange, onClear, ...args }) {
    const triggerRef = useRef<HTMLButtonElement | null>(null);
    const [selectedMonth, setSelectedMonth] = useState<TestMonth | null>(null);

    useEffect(() => {
      const timer = setTimeout(() => {
        triggerRef.current?.click();
      }, 200);
      return () => clearTimeout(timer);
    }, []);

    return (
      <SelectInput
        {...args}
        triggerRef={triggerRef}
        value={selectedMonth}
        onChange={(month) => {
          setSelectedMonth(month);
          onChange?.(month);
        }}
        onClear={() => {
          setSelectedMonth(null);
          onClear?.();
        }}
      />
    );
  },
  args: {
    placeholder: 'Month',
    items: testMonths.map((month) => ({
      type: 'option',
      value: month,
    })),
    renderValue: (month) => <SelectInputOptionContent title={month.name} />,
  },
  ...withVariantConfig(['400%']),
};

const jpy = { code: 'JPY', name: 'Japanese yen' } satisfies TestCurrency;
const flagClippingItems = [testCurrencyOption(jpy)];
const flagClippingArgs = {
  items: flagClippingItems,
  value: jpy,
  size: 'lg',
  renderValue: (currency: TestCurrency) => (
    <SelectInputOptionContent
      title={currency.code}
      icon={<Flag code={currency.code} intrinsicSize={24} />}
    />
  ),
} satisfies Story<TestCurrency>['args'];

const singleCurrencyMoneyInputProps = {
  id: 'flag-clipping-money-input',
  amount: 1234.14,
  currencies: [],
  selectedCurrency: {
    value: 'EUR',
    label: 'EUR',
    note: 'Euro',
    currency: 'eur',
    searchable: 'Spain, Germany, France, Austria',
  },
  onAmountChange: fn() satisfies Mock,
  onCurrencyChange: fn() satisfies Mock,
};

export const FlagClipping: Story<TestCurrency> = {
  render: (args) => (
    <div style={{ display: 'grid', gap: 24, width: 360 }}>
      <Field label="Flag clipping">
        <SelectInput {...args} />
      </Field>
    </div>
  ),
  args: flagClippingArgs,
};
