import {
  Button,
  FormControl,
  FormLabel,
  FormErrorMessage,
  HStack,
  Input,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
  NumberDecrementStepper,
  NumberIncrementStepper,
  NumberInput,
  NumberInputField,
  NumberInputStepper,
  Switch,
  VStack,
  InputGroup,
  InputRightAddon,
  Divider,
  IconButton,
  Flex,
} from '@chakra-ui/react';
import { useEffect } from 'react';
import { Form, useFormik } from 'formik';
import * as Yup from 'yup';

import { EVENT_NAMES, VIEW_ACTION_TYPES } from '../../../constants/define';
import { SELECT_TYPES } from '../../../modules/tracker/constants';
import { Select } from 'chakra-react-select';
import { DeleteIcon } from '@chakra-ui/icons';
import { findLast } from 'lodash';
import { FormattedCodeViewer } from '..';

const { INDICATE_SELECTOR, DETAIL_COLUMN_TABLE_RECORD, ON_UPDATE_SELECTOR, ON_UPDATE_DETAIL_SCRAPE_COLUMN } =
  EVENT_NAMES.CLIENT_RECORDER;
const { REMOVE_EVENT_LISTENER } = EVENT_NAMES.COMMON;

const validationSchema = Yup.object().shape({
  isTable: Yup.boolean(),
  isExtractAdditionalInfoDetail: Yup.boolean(),
  hasPagination: Yup.boolean(),
  linkColumnPosition: Yup.number().when('isExtractAdditionalInfoDetail', {
    is: true,
    then: () => Yup.number().required('Link Column Position is required'),
    otherwise: () => Yup.number().notRequired(),
  }),
  detailScrapeInstructions: Yup.string().when('isExtractAdditionalInfoDetail', {
    is: true,
    then: () => Yup.array().required('Detail Scrape Instructions is required'),
    otherwise: () => Yup.array().notRequired(),
  }),
  // selector: Yup.string().required('Selector is required'),
  selector: Yup.string().when('isTable', {
    is: true,
    then: () => Yup.string().required('Selector is required'),
    otherwise: () => Yup.string().notRequired(),
  }),
  paginationSelector: Yup.string().when('hasPagination', {
    is: true,
    then: () => Yup.string().required('Pagination Selector is required'),
    otherwise: () => Yup.string().notRequired(),
  }),
  nextPageSelector: Yup.string().when('hasPagination', {
    is: true,
    then: () => Yup.string().required('Next Page Selector is required'),
    otherwise: () => Yup.string().notRequired(),
  }),
  paginatedStart: Yup.number().when('hasPagination', {
    is: true,
    then: () => Yup.number().required('Paginate Start is required'),
    otherwise: () => Yup.number().notRequired(),
  }),
  paginatedEnd: Yup.number().when('hasPagination', {
    is: true,
    then: () =>
      Yup.number()
        .min(Yup.ref('paginatedStart'), 'Paginate End cannot be lower than Paginate Start')
        .required('Paginate End is required'),
    otherwise: () => Yup.number().notRequired(),
  }),
  selectedFields: Yup.array().when('isTable', {
    is: false,
    then: () => Yup.array().required('Selected Fields is required'),
    otherwise: () => Yup.array().notRequired(),
  }),
});

export default function ConfigPaginationStepModal({ eventLogs, step, isOpen, onClose, onSave }) {
  const extractEvent = step,
    formik = useFormik({
      initialValues: {
        ...extractEvent,
        isTable: extractEvent?.isTable || false,
        selector: extractEvent?.selector || '',
        paginationSelector: extractEvent?.paginationSelector || '',
        nextPageSelector: extractEvent?.nextPageSelector || '',
        paginatedStart: extractEvent?.paginatedStart || '1',
        paginatedEnd: extractEvent?.paginatedEnd || '1',
        hasPagination: extractEvent?.hasPagination || false,
        selectedFields: extractEvent?.selectedFields || [],
        detailScrapeInstructions: '',
      },
      validationSchema,
      onSubmit: handleSubmit,
    });

  const handleReSelectSelector = async (reSelectType) => {
    const newEventLog = eventLogs?.map((event) => {
      if (event?.id === step?.id) {
        return {
          ...event,
          ...formik.values,
          ...(SELECT_TYPES.EXTRACT_DATA === reSelectType && { selector: '' }),
          ...(SELECT_TYPES.SELECT_PAGINATION_SELECTOR === reSelectType && { paginationSelector: '' }),
          ...(SELECT_TYPES.SELECT_NEXT_PAGE_SELECTOR === reSelectType && { nextPageSelector: '' }),
        };
      }
      return event;
    });

    await window?.recorder[INDICATE_SELECTOR](newEventLog, step?.id, reSelectType);
  };

  const handleRecordDetailColumn = async () => {
    const newEventLog = eventLogs?.map((event) => {
      if (event?.id === step?.id) {
        return {
          ...event,
          ...formik.values,
        };
      }
      return event;
    });

    await window?.recorder[DETAIL_COLUMN_TABLE_RECORD](newEventLog, step?.id, formik.values.linkColumnPosition);
  };

  function handleSubmit(values) {
    onSave({ ...step, ...values });
    onClose();
  }

  useEffect(() => {
    const updateEventLog = (_, type, selector, store) => {
      const lastEvent = findLast(store.recording, (event) => event?.action === 'extract-data');
      formik.setFieldValue('isTable', lastEvent?.isTable);
      formik.setFieldValue('hasPagination', !!lastEvent?.hasPagination);
      formik.setFieldValue('selector', lastEvent?.selector || '');
      formik.setFieldValue('paginationSelector', lastEvent?.paginationSelector || '');
      formik.setFieldValue('nextPageSelector', lastEvent?.nextPageSelector || '');
      formik.setFieldValue('selectedFields', lastEvent?.selectedFields || []);
    };
    const updateRecordDetailColumn = (_, detailRecording) => {
      if (detailRecording?.length > 0) {
        formik.setFieldValue('detailScrapeInstructions', JSON.stringify(detailRecording));
      }
    };

    window.recorder[ON_UPDATE_SELECTOR](updateEventLog);
    window.recorder[ON_UPDATE_DETAIL_SCRAPE_COLUMN](updateRecordDetailColumn);

    return () => {
      window.common[REMOVE_EVENT_LISTENER](ON_UPDATE_SELECTOR, updateEventLog);
      window.common[REMOVE_EVENT_LISTENER](ON_UPDATE_DETAIL_SCRAPE_COLUMN, updateRecordDetailColumn);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    formik.resetForm({
      values: {
        ...extractEvent,
      },
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [JSON.stringify(extractEvent)]);

  useEffect(() => {
    console.log({
      errors: formik.errors,
    });
  }, [formik.touched, formik.errors]);

  function handleCloseModal() {
    formik.resetForm();
    window.common[EVENT_NAMES.COMMON.CLOSE_WINDOW]();
    onClose();
  }

  return (
    <Modal
      onCloseComplete={() => {
        formik.resetForm();
      }}
      size="4xl"
      isCentered
      isOpen={isOpen}
      onClose={handleCloseModal}
    >
      <ModalOverlay />
      <ModalContent>
        <ModalHeader>Configure Extract Step</ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          <Form>
            <VStack alignItems="stretch">
              <HStack>
                <FormControl>
                  <FormLabel wordBreak="unset">Is Table?</FormLabel>
                  <Switch
                    isChecked={formik.values.isTable}
                    onChange={(e) => formik.setFieldValue('isTable', e.target.checked)}
                  />
                </FormControl>
                {formik.values.isTable && (
                  <>
                    <FormControl>
                      <FormLabel wordBreak="keep-all">Using Pagination</FormLabel>
                      <Switch
                        isChecked={formik.values.hasPagination}
                        onChange={(e) => formik.setFieldValue('hasPagination', e.target.checked)}
                      />
                    </FormControl>
                    <FormControl>
                      <FormLabel wordBreak="keep-all">Extract Additional Info Detail</FormLabel>
                      <Switch
                        isChecked={formik.values.isExtractAdditionalInfoDetail}
                        onChange={(e) => formik.setFieldValue('isExtractAdditionalInfoDetail', e.target.checked)}
                      />
                    </FormControl>
                  </>
                )}
              </HStack>
              <Divider />
              {formik.values.isTable ? (
                <FormControl
                  isRequired
                  isInvalid={!!formik.errors.selector && formik.touched.selector}
                  marginBottom="1rem"
                >
                  <FormLabel>Indicate Extract Element</FormLabel>
                  <InputGroup borderRadius={5}>
                    <Input
                      placeholder="Selector..."
                      onChange={formik.handleChange}
                      type="text"
                      border="1px solid #949494"
                      {...formik.getFieldProps('selector')}
                    />
                    <InputRightAddon p={0} border="none">
                      <Button
                        colorScheme="primary"
                        borderLeftRadius={0}
                        borderRightRadius={3.3}
                        border="1px solid #949494"
                        onClick={() => handleReSelectSelector(SELECT_TYPES.EXTRACT_DATA)}
                      >
                        Re-Indicate
                      </Button>
                    </InputRightAddon>
                  </InputGroup>
                  <FormErrorMessage>{formik.errors.selector}</FormErrorMessage>
                </FormControl>
              ) : (
                <>
                  {formik.values.selectedFields?.map((field, index) => (
                    <FormControl
                      key={index}
                      isRequired
                      isInvalid={!!formik.errors.selectedFields && formik.touched.selectedFields}
                      marginBottom="1rem"
                    >
                      <FormLabel>Field {index + 1}</FormLabel>
                      <HStack>
                        <Input
                          flex={1}
                          placeholder={`Field ${index + 1}`}
                          handleChange={formik.handleChange}
                          {...formik.getFieldProps(`selectedFields[${index}].name`)}
                        />
                        <InputGroup flex={5} borderRadius={5}>
                          <Input
                            placeholder="Selector"
                            type="text"
                            handleChange={formik.handleChange}
                            {...formik.getFieldProps(`selectedFields[${index}].selector`)}
                          />
                          <InputRightAddon
                            onClick={() => {
                              formik.setFieldValue(
                                'selectedFields',
                                formik.values.selectedFields.filter((item) => {
                                  return field?.id !== item?.id;
                                }),
                              );
                            }}
                            p={0}
                            border="none"
                          >
                            <IconButton
                              borderLeftRadius={0}
                              icon={<DeleteIcon />}
                              borderRightColor={3.3}
                              colorScheme="red"
                            />
                          </InputRightAddon>
                        </InputGroup>
                      </HStack>
                    </FormControl>
                  ))}
                </>
              )}
              {formik.values.isTable && formik.values.hasPagination && (
                <>
                  <FormControl
                    isInvalid={!!formik.errors.paginationSelector && formik.touched.paginationSelector}
                    marginBottom="1rem"
                  >
                    <FormLabel>Indicate The Pagination Element for Table</FormLabel>
                    <InputGroup borderRadius={5}>
                      <Input
                        placeholder="Pagination Selector..."
                        onChange={formik.handleChange}
                        type="text"
                        border="1px solid #949494"
                        {...formik.getFieldProps('paginationSelector')}
                      />
                      <InputRightAddon p={0} border="none">
                        <Button
                          colorScheme="primary"
                          borderLeftRadius={0}
                          borderRightRadius={3.3}
                          border="1px solid #949494"
                          onClick={() => handleReSelectSelector(SELECT_TYPES.SELECT_PAGINATION_SELECTOR)}
                        >
                          Re-Indicate
                        </Button>
                      </InputRightAddon>
                    </InputGroup>
                    <FormErrorMessage>{formik.errors.paginationSelector}</FormErrorMessage>
                  </FormControl>
                  <FormControl
                    isInvalid={!!formik.errors.nextPageSelector && formik.touched.nextPageSelector}
                    marginBottom="1rem"
                  >
                    <FormLabel>Indicate The Next Button Element</FormLabel>
                    <InputGroup borderRadius={5}>
                      <Input
                        placeholder="Selector..."
                        type="text"
                        border="1px solid #949494"
                        onChange={formik.handleChange}
                        {...formik.getFieldProps('nextPageSelector')}
                      />
                      <InputRightAddon p={0} border="none">
                        <Button
                          colorScheme="primary"
                          borderLeftRadius={0}
                          borderRightRadius={3.3}
                          border="1px solid #949494"
                          onClick={() => handleReSelectSelector(SELECT_TYPES.SELECT_NEXT_PAGE_SELECTOR)}
                        >
                          Re-Indicate
                        </Button>
                      </InputRightAddon>
                    </InputGroup>
                    <FormErrorMessage>{formik.errors.nextPageSelector}</FormErrorMessage>
                  </FormControl>
                  <HStack alignItems="flex-start">
                    <FormControl
                      isRequired
                      isInvalid={!!formik.errors.paginatedStart && formik.touched.paginatedStart}
                      marginBottom="1rem"
                    >
                      <FormLabel>Paginated Start</FormLabel>
                      <NumberInput
                        value={formik.values.paginatedStart}
                        onChange={(value) => formik.setFieldValue('paginatedStart', value)}
                      >
                        <NumberInputField />
                        <NumberInputStepper>
                          <NumberIncrementStepper />
                          <NumberDecrementStepper />
                        </NumberInputStepper>
                      </NumberInput>
                      <FormErrorMessage>{formik.errors.paginatedEnd}</FormErrorMessage>
                    </FormControl>
                    <FormControl
                      isRequired
                      isInvalid={!!formik.errors.paginatedEnd && formik.touched.paginatedEnd}
                      marginBottom="1rem"
                    >
                      <FormLabel>Paginated End</FormLabel>

                      <NumberInput
                        value={formik.values.paginatedEnd}
                        onChange={(value) => formik.setFieldValue('paginatedEnd', value)}
                      >
                        <NumberInputField />
                        <NumberInputStepper>
                          <NumberIncrementStepper />
                          <NumberDecrementStepper />
                        </NumberInputStepper>
                      </NumberInput>
                      <FormErrorMessage>{formik.errors.paginatedEnd}</FormErrorMessage>
                    </FormControl>
                  </HStack>
                </>
              )}
              {formik.values.isTable && formik.values.isExtractAdditionalInfoDetail && (
                <>
                  <Divider />
                  <h1>Additional Info Detail</h1>
                  <FormControl>
                    <FormLabel>Indicate The Element</FormLabel>
                    <Flex gap="5">
                      <NumberInput
                        flex="1"
                        value={formik.values.linkColumnPosition}
                        onChange={(value) => formik.setFieldValue('linkColumnPosition', value)}
                      >
                        <NumberInputField />
                        <NumberInputStepper>
                          <NumberIncrementStepper />
                          <NumberDecrementStepper />
                        </NumberInputStepper>
                      </NumberInput>
                      <Button colorScheme="primary" onClick={handleRecordDetailColumn} width="fit-content">
                        Detail Record
                      </Button>
                    </Flex>
                  </FormControl>
                  <FormattedCodeViewer
                    formatOption={VIEW_ACTION_TYPES.JSON}
                    formatedCode={formik.values.detailScrapeInstructions || []}
                  />
                </>
              )}
              {formik.values.isTable && (
                <>
                  <Divider />
                  <FormControl>
                    <FormLabel>Merge Data With</FormLabel>
                    <Select
                      isMulti
                      options={eventLogs
                        ?.filter((event) => event?.action === 'extract-data' && event?.id !== step?.id)
                        ?.map((event) => ({
                          value: event?.id,
                          label: `Extract Step from ${event?.id}`,
                        }))}
                    />
                  </FormControl>
                </>
              )}
            </VStack>
          </Form>
        </ModalBody>
        <ModalFooter>
          <Button onClick={() => handleReSelectSelector()} colorScheme="primary" mr={3}>
            Re-Indicate
          </Button>
          <Button isDisabled={!formik.dirty} colorScheme="primary" mr={3} onClick={formik.submitForm}>
            Save
          </Button>
          <Button variant="ghost" onClick={handleCloseModal}>
            Cancel
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  );
}
