import { useState } from 'react';
import { useForm } from 'react-hook-form';
import {
  QueryClient,
  QueryClientProvider,
  useInfiniteQuery,
} from 'react-query';

import FormWrapper from '@composed-components/storybook/FormWrapper';
import { useDrawerV2 } from '@hooks/useDrawerV2';
import { type Meta, type StoryObj } from '@storybook/react-vite';

import usersService from '../../../../mock/services/users';
import { mockDataParser, useMockUsersQuery } from '../mocks';

const useSlowUsersQuery = (search: string) =>
  useInfiniteQuery({
    queryKey: ['slowMockUsers', search],
    queryFn: async ({ pageParam }) => {
      // Extra 1.5 s delay on top of the default 500 ms to make the loading
      // skeleton clearly visible during search re-fetches.
      await new Promise(resolve => setTimeout(resolve, 1500));
      return usersService.getUsers(pageParam, 5, search);
    },
    getNextPageParam: lastPage => lastPage.nextCursor,
    keepPreviousData: true,
    staleTime: 0,
  });

import FormIndividualSelection from './form';
import { type IndividualSelectionProps } from './types';
import IndividualSelection from './index';

type StoryComponentArgs = Omit<
  IndividualSelectionProps,
  'usersQuery' | 'usersQueryDataParser'
> & { empty?: boolean };

const IndividualSelectionWithMockQuery = ({
  empty,
  ...props
}: StoryComponentArgs) => {
  const [selectedAll, setSelectedAll] = useState(props.selectedAll);
  const [search, setSearch] = useState('');
  const [selectedUserIds, setSelectedUserIds] = useState(props.value);
  const usersQuery = useMockUsersQuery(search, empty);

  const filterDrawer = useDrawerV2(() => {
    return {
      title: 'Filtros de Segmentación',
      children: <div>Contenido del drawer de filtros</div>,
      primaryButtonProps: {
        children: 'Guardar cambios',
        onClick: () => filterDrawer.closeDrawer(),
      },
      secondaryButtonProps: {
        children: 'Limpiar filtros',
        onClick: () => filterDrawer.closeDrawer(),
      },
    };
  });

  return (
    <>
      <pre>{JSON.stringify(Array.from(selectedUserIds || []))}</pre>
      {filterDrawer.drawer}
      <IndividualSelection
        {...props}
        slotProps={{
          ...props.slotProps,
          filterButton: {
            ...props.slotProps?.filterButton,
            onClick: () => filterDrawer.showDrawer({}),
          },
        }}
        usersQuery={usersQuery}
        usersQueryDataParser={mockDataParser}
        value={selectedUserIds}
        searchValue={search}
        onSearch={setSearch}
        onSelectAll={setSelectedAll}
        selectedAll={selectedAll}
        onChange={setSelectedUserIds}
      />
    </>
  );
};

const meta: Meta<typeof IndividualSelectionWithMockQuery> = {
  component: IndividualSelectionWithMockQuery,
  title: 'Composed Components/Audience/IndividualSelection',
  tags: ['autodocs'],
  decorators: [
    Story => {
      const queryClient = new QueryClient({
        defaultOptions: {
          queries: {
            retry: false,
          },
        },
      });

      return (
        <QueryClientProvider client={queryClient}>
          <div style={{ height: '400px', width: '100%' }}>
            <Story />
          </div>
        </QueryClientProvider>
      );
    },
  ],
  args: {
    selectionLimit: 3,
    filterCount: 0,
    value: new Set([1, 3]),
    slotProps: {
      search: {
        placeholder: 'Buscar usuario',
      },
      title: {
        title: 'Selección Individual',
        description: 'Selecciona usuarios específicos para tu audiencia',
      },
      filterButton: {
        children: 'Filtros',
      },
      selectAllCheckbox: {
        label: 'Seleccionar todo',
      },
      emptyStateCard: {
        title: 'No hay usuarios disponibles',
        description:
          'No se encontraron usuarios que coincidan con los criterios de búsqueda',
      },
      infiniteListLoaderButton: {
        children: 'Cargar más',
      },
      userAvatar: {
        profileProps: {
          showEmail: true,
        },
      },
    },
  },
};

export default meta;

type Story = StoryObj<typeof IndividualSelectionWithMockQuery>;

export const Default: Story = {};

const FormIndividualSelectionStory = ({
  empty,
  ...props
}: StoryComponentArgs) => {
  const form = useForm({
    defaultValues: {
      selectedUsers: new Set([1, 3]),
      search: '',
    },
  });

  const search = form.watch('search');
  const usersQuery = useMockUsersQuery(search, empty);

  return (
    <FormWrapper form={form}>
      <FormIndividualSelection
        name="selectedUsers"
        searchName="search"
        inputProps={{
          ...props,
          usersQuery,
          usersQueryDataParser: mockDataParser,
          slotProps: props.slotProps,
        }}
      />
    </FormWrapper>
  );
};

export const WithForm: Story = {
  render: args => <FormIndividualSelectionStory {...args} />,
  parameters: {
    docs: {
      description: {
        story:
          'Usage with `FormIndividualSelection` integrated into react-hook-form. ' +
          'The selected user IDs and search text are managed by the form state.',
      },
    },
  },
};

const IndividualSelectionSlowQuery = (props: StoryComponentArgs) => {
  const [search, setSearch] = useState('');
  const [selectedUserIds, setSelectedUserIds] = useState(props.value);
  const usersQuery = useSlowUsersQuery(search);

  return (
    <IndividualSelection
      {...props}
      usersQuery={usersQuery}
      usersQueryDataParser={mockDataParser}
      value={selectedUserIds}
      searchValue={search}
      onSearch={setSearch}
      onChange={setSelectedUserIds}
    />
  );
};

export const LoadingOnFilterChange: Story = {
  name: 'Skeleton on search re-fetch (not on pagination)',
  render: args => <IndividualSelectionSlowQuery {...args} />,
  parameters: {
    docs: {
      description: {
        story:
          'Uses a slow query (2 s per fetch) to make the loading states observable. ' +
          '**Type in the search box** → the skeleton list replaces the current results while ' +
          'the new page loads (`isFetching && !isFetchingNextPage`). ' +
          '**Click "Cargar más"** → the list stays visible and only the loader button changes, ' +
          'because `isFetchingNextPage` is true so `isLoadingUsers` stays false.',
      },
    },
  },
};

const OnSelectAllCallbackStory = (props: StoryComponentArgs) => {
  const [search, setSearch] = useState('');
  const [selectedUserIds, setSelectedUserIds] = useState(props.value);
  const [lastOnSelectAllValue, setLastOnSelectAllValue] = useState<
    boolean | undefined
  >(undefined);
  const [callCount, setCallCount] = useState(0);
  const usersQuery = useMockUsersQuery(search);

  const handleSelectAll = (value?: boolean) => {
    setLastOnSelectAllValue(value);
    setCallCount(prev => prev + 1);
  };

  return (
    <div style={{ display: 'flex', gap: 16, height: '100%' }}>
      <div style={{ flex: 1 }}>
        <IndividualSelection
          {...props}
          usersQuery={usersQuery}
          usersQueryDataParser={mockDataParser}
          value={selectedUserIds}
          searchValue={search}
          onSearch={setSearch}
          onChange={setSelectedUserIds}
          onSelectAll={handleSelectAll}
        />
      </div>
      <div
        style={{
          padding: 16,
          background: '#f5f5f5',
          borderRadius: 8,
          minWidth: 200,
          alignSelf: 'flex-start',
        }}
      >
        <strong>onSelectAll callback</strong>
        <pre style={{ marginTop: 8, fontSize: 13 }}>
          {`calls: ${callCount}\nlast value: ${lastOnSelectAllValue === undefined ? 'never called' : String(lastOnSelectAllValue)}`}
        </pre>
      </div>
    </div>
  );
};

export const OnSelectAllCallback: Story = {
  name: 'onSelectAll callback',
  render: args => <OnSelectAllCallbackStory {...args} />,
  parameters: {
    docs: {
      description: {
        story:
          'Verifies the `onSelectAll` callback fires when the select-all checkbox is toggled. ' +
          'The panel on the right shows how many times the callback was called and the last value it received (`true` when selecting all, `false` when deselecting).',
      },
    },
  },
};
