import type { Meta, StoryObj } from '@storybook/react-webpack5';
import { within, userEvent, fireEvent, expect } from 'storybook/test';
import { allModes } from '../../.storybook/modes';
import { lorem500 } from '../test-utils';
import { Field } from '../field/Field';
import Body from '../body';
import MoneyInput from './MoneyInput';

const meta = {
  title: 'Forms/MoneyInput/Tests',
  component: MoneyInput,
  args: {
    amount: 1000,
    id: 'moneyInput',
    currencies: [
      {
        value: 'EUR',
        label: 'EUR',
        note: 'Euro',
        currency: 'eur',
        searchable: 'Spain, Germany, France, Austria',
      },
      {
        value: 'GBP',
        label: 'GBP',
        note: 'British pound',
        currency: 'gbp',
        searchable: 'England, Scotland, Wales',
      },
    ],
    selectedCurrency: {
      value: 'EUR',
      label: 'EUR',
      note: 'Euro',
      currency: 'eur',
      searchable: 'Spain, Germany, France, Austria',
    },
    searchPlaceholder: '',
    onAmountChange: () => {},
    onCurrencyChange: () => {},
  },
  tags: ['!autodocs'],
} satisfies Meta<typeof MoneyInput>;
export default meta;

type Story = StoryObj<typeof MoneyInput>;

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

/**
 * 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 = {
  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="Select currency">
            <Story />
          </Field>
          <Body as="p">{lorem500}</Body>
        </div>
      </>
    ),
  ],
  play: async ({ canvasElement }) => {
    await wait();
    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,
    },
  },
};

export const WithDecimals: Story = {
  args: {
    currencies: [],
    decimals: 4,
    amount: 1234.5678,
  },
  play: async ({ canvas }) => {
    const input = canvas.getByRole('textbox');
    await expect(input).toHaveValue('1,234.5678');
    await userEvent.clear(input);
    await userEvent.type(input, '99.123456789');
    await userEvent.tab();
    await expect(input).toHaveValue('99.1235');
  },
};

const eur = {
  value: 'EUR',
  label: 'EUR',
  note: 'Euro',
  currency: 'eur',
} as const;

const bhd = {
  value: 'BHD',
  label: 'BHD',
  note: 'Bahraini dinar',
  currency: 'bhd',
} as const;

const jpy = {
  value: 'JPY',
  label: 'JPY',
  note: 'Japanese yen',
  currency: 'jpy',
} as const;

const sharedProps = {
  currencies: [],
  onAmountChange: () => {},
  onCurrencyChange: () => {},
} as const;

function Row({
  label,
  amount,
  currency,
  decimals,
}: {
  label: string;
  amount: number;
  currency: { value: string; label: string; note: string; currency: string };
  decimals: number;
}) {
  return (
    <div
      style={{
        display: 'grid',
        gridTemplateColumns: '240px 1fr 1fr',
        gap: 12,
        alignItems: 'center',
      }}
    >
      <Body as="span" style={{ fontSize: 13, color: '#6b7280' }}>
        {label}
      </Body>
      <Field label={`No decimals prop (${currency.value})`}>
        <MoneyInput {...sharedProps} selectedCurrency={currency} amount={amount} />
      </Field>
      <Field label={`decimals={${decimals}} (${currency.value})`}>
        <MoneyInput
          {...sharedProps}
          selectedCurrency={currency}
          amount={amount}
          decimals={decimals}
        />
      </Field>
    </div>
  );
}

/**
 * Side-by-side comparison of formatAmount (no decimals prop) vs formatNumber (with decimals prop)
 * when decimals matches the currency default. Differences indicate a formatting parity issue.
 *
 * Problem 1: Trailing zero stripping — formatAmount strips ".00" for whole numbers,
 * formatNumber always pads to the requested precision.
 *
 * Problem 2: BHD decimal count — formatAmount renders 2 fractional digits for BHD,
 * but the currencyDecimals map says BHD has 3. formatNumber with decimals=3 shows 3.
 */
export const DecimalsFormatParity: Story = {
  render: () => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
        EUR — whole numbers (trailing zero stripping)
      </Body>
      <Row label="amount=0" amount={0} currency={eur} decimals={2} />
      <Row label="amount=1" amount={1} currency={eur} decimals={2} />
      <Row label="amount=42" amount={42} currency={eur} decimals={2} />
      <Row label="amount=100" amount={100} currency={eur} decimals={2} />
      <Row label="amount=1000" amount={1000} currency={eur} decimals={2} />
      <Row label="amount=9999999" amount={9999999} currency={eur} decimals={2} />

      <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
        EUR — fractional amounts (should match)
      </Body>
      <Row label="amount=0.01" amount={0.01} currency={eur} decimals={2} />
      <Row label="amount=0.1" amount={0.1} currency={eur} decimals={2} />
      <Row label="amount=99.9" amount={99.9} currency={eur} decimals={2} />
      <Row label="amount=1234567.89" amount={1234567.89} currency={eur} decimals={2} />

      <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
        BHD — all amounts (formatAmount uses 2 digits, formatNumber uses 3)
      </Body>
      <Row label="amount=0" amount={0} currency={bhd} decimals={3} />
      <Row label="amount=0.001" amount={0.001} currency={bhd} decimals={3} />
      <Row label="amount=0.01" amount={0.01} currency={bhd} decimals={3} />
      <Row label="amount=0.1" amount={0.1} currency={bhd} decimals={3} />
      <Row label="amount=42" amount={42} currency={bhd} decimals={3} />
      <Row label="amount=99.9" amount={99.9} currency={bhd} decimals={3} />
      <Row label="amount=999.99" amount={999.99} currency={bhd} decimals={3} />
      <Row label="amount=1234567.89" amount={1234567.89} currency={bhd} decimals={3} />

      <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
        JPY — zero-decimal currency (should always match)
      </Body>
      <Row label="amount=0" amount={0} currency={jpy} decimals={0} />
      <Row label="amount=1" amount={1} currency={jpy} decimals={0} />
      <Row label="amount=1000" amount={1000} currency={jpy} decimals={0} />
      <Row label="amount=1234567" amount={1234567} currency={jpy} decimals={0} />
    </div>
  ),
  parameters: {
    chromatic: {
      disableSnapshot: true,
    },
  },
};
