import { useForm } from 'react-hook-form';
import { useState, useContext, useEffect, useRef } from 'react';
import { initialValues, validationSchema } from './utils/schemaValidation';
import { registerEvents } from 'src/store/apps/events';
import { updateEvents } from 'src/store/apps/events';
import { AuthContext } from 'src/context/AuthContext';
import { getCategoriesbyType } from 'src/store/apps/categories';
import { getTimezones } from 'src/store/apps/timezones';
import { getByName as getTagsByName } from 'src/store/apps/tags';
import moment from 'moment';
import { useRouter } from 'next/router';
import { Loader } from '@googlemaps/js-api-loader';
import getConfig from 'next/config';
import { yupResolver } from '@hookform/resolvers/yup';
import Swal from 'sweetalert2';
import { useTranslation } from 'react-i18next';
import { getEventAdapter } from 'src/views/forms/form-events/utils/get-event.adapter';
import { CogSyncOutline, Marker } from 'mdi-material-ui';
import toast from 'react-hot-toast';

const typeItems = [
  { value: 1, label: 'Dinner or Gala' },
  { value: 2, label: 'Party or Social Gathering' },
];

export function useFormEvents(id, data, updateData) {
  const { t } = useTranslation();
  const [loading, setLoading] = useState(false);
  const { user } = useContext(AuthContext);
  const [categories, setCategories] = useState([]);
  const [timezones, setTimezones] = useState([]);
  const [type, setType] = useState(1);
  const [tagsItems, setTagsItems] = useState([]);
  const router = useRouter();
  const { publicRuntimeConfig } = getConfig();
  const [place, setPlace] = useState(null);
  const apikeyPlaces = publicRuntimeConfig.PLACES_MAP_KEY;
  const [lat, setLat] = useState(null);
  const [lng, setLng] = useState(null);

  const refs = {
    location: useRef(null),
    longitude: useRef(null),
    latitude: useRef(null),
    city: useRef(null),
    state: useRef(null),
    country: useRef(null),
    zipCode: useRef(null),
    streetAddressTwo: useRef(null),
    streetAddressOne: useRef(null),
    location: useRef(null),
    map: useRef(null),
  };

  const handleCancel = () => {
    Swal.fire({
      title: '¿Estás seguro?',
      text: 'Si realizaste algun registro, se perderá',
      icon: 'warning',
      showCancelButton: true,
      confirmButtonText: 'Si, estoy seguro',
      cancelButtonText: 'No',
    }).then(result => {
      if (result.isConfirmed) {
        router.push('/apps/events/list/');
      }
    });
  };

  const cancelUpdate = () => {
    Swal.fire({
      title: '¿Estás seguro?',
      text: 'Restablecerá los datos del formulario',
      icon: 'warning',
      showCancelButton: true,
      confirmButtonText: 'Si, estoy seguro',
      cancelButtonText: 'No',
    }).then(result => {
      if (result.isConfirmed) {
        isUpdate(data);
      }
    });
  };

  const loader = new Loader({
    apiKey: apikeyPlaces,
    version: 'weekly',
    libraries: ['places', 'maps', 'marker', 'geocoding '],
  });

  const {
    control,
    setValue,
    reset,
    getValues,
    handleSubmit,
    formState: { errors },
  } = useForm({
    defaultValues: initialValues,
    resolver: yupResolver(validationSchema),
  });

  const venue = () => {
    setType(1);
    setValue('type', 1);
  };

  const onlineEvent = () => {
    setType(2);
    setPlace(null);
    setLat(null);
    setLng(null);
    setValue('type', 2);
    setValue('streetAddressOne', '');
    setValue('streetAddressTwo', '');
    setValue('location', '');
    setValue('city', '');
    setValue('state', '');
    setValue('country', '');
    setValue('zipCode', '');
  };

  const searchTag = async name => {
    const { status, data } = await getTagsByName(name);
    if (status === 200) {
      const { tags } = data;

      const newTags = tags.map(tag => {
        return {
          value: tag?.id,
          label: tag?.name,
          select: {
            name: tag?.id ? tag?.name : `Add "${tag?.name}" as a new tag`,
          },
        };
      });

      setTagsItems(newTags);
    } else {
      onError({ status, data });
    }
  };

  const onChangePlace = (place, lat, lng) => {
    setPlace(place);
    setValue('streetAddressOne', place.formatted_address);
    setValue('location', place.name);
    setLat(lat);
    setLng(lng);
    for (let component of place.address_components) {
      if (component.types.includes('locality')) {
        setValue('city', component.long_name);
      } else if (component.types.includes('administrative_area_level_1')) {
        setValue('state', component.long_name);
      } else if (component.types.includes('country')) {
        setValue('country', component.long_name);
      } else if (component.types.includes('postal_code')) {
        setValue('zipCode', component.long_name);
      }
    }
  };

  const initPlace = () => {
    loader
      .importLibrary('places')
      .then(({ Autocomplete }) => {
        const autocomplete = new Autocomplete(refs.location.current, {
          fields: ['place_id', 'formatted_address', 'name', 'address_components', 'geometry'],
        });

        autocomplete.addListener('place_changed', () => {
          const place = autocomplete.getPlace();
          onChangePlace(place, place.geometry.location.lat(), place.geometry.location.lng());
        });
      })
      .catch(e => {});
  };

  const getPlacewhitooutMarker = (PlacesService, placeId, map, lat, lng) => {
    const service = new PlacesService(map);
    service.getDetails({ placeId }, (place, status) => {
      if (status === 'OK') {
        onChangePlace(place, lat, lng);
      }
    });
  };

  const getPlace = (Marker, PlacesService, markerView, placeId, map) => {
    const service = new PlacesService(map);
    service.getDetails({ placeId }, (place, status) => {
      if (status === 'OK') {
        markerView.setMap(null);

        const marker = new Marker({
          map,
          position: { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() },
        });
        onChangePlace(place, place.geometry.location.lat(), place.geometry.location.lng());
      }
    });
  };

  const getEditPlace = (Marker, PlacesService, markerView, placeId, map) => {
    const service = new PlacesService(map);
    service.getDetails({ placeId }, (place, status) => {
      if (status === 'OK') {
        markerView.setMap(null);

        const marker = new Marker({
          map,
          position: { lat: lat, lng: lng },
        });
        onChangePlace(place, lat, lng);
      }
    });
  };

  const initMap = () => {
    // Promise for a specific library
    loader
      .load()
      .then(async () => {
        const { Map } = await google.maps.importLibrary('maps');
        const { Marker } = await google.maps.importLibrary('marker');
        const { PlacesService } = await google.maps.importLibrary('places');
        const { Geocoder } = await google.maps.importLibrary('geocoding');

        const map = new Map(refs.map.current, {
          center: { lat: lat, lng: lng },
          zoom: 18,
        });

        const markerView = new Marker({
          map,
          position: { lat: lat, lng: lng },
          draggable: true,
        });

        markerView.addListener('dragend', event => {
          const geocoder = new Geocoder();
          geocoder.geocode({ location: event.latLng }, (results, status) => {
            Swal.fire({
              title: 'Atencion',
              text: 'Mover el marcador no rellena los campos de forma exacta, verificar la informacion antes de guardar',
              icon: 'warning',
            });
            if (status === 'OK') {
              for (results of results) {
                if (results.geometry.location_type.includes('RANGE_INTERPOLATED')) {
                  getPlacewhitooutMarker(PlacesService, results.place_id, map, event.latLng.lat(), event.latLng.lng());
                }
              }
            }
          });
        });

        if (data?.googlePlaceId && place?.formatted_address === undefined) {
          getEditPlace(Marker, PlacesService, markerView, data?.googlePlaceId, map);
        }

        map.addListener('click', ({ domEvent, latLng, placeId }) => {
          const { target } = domEvent;
          if (placeId) {
            getPlace(Marker, PlacesService, markerView, placeId, map);
          } else {
            const geocoder = new Geocoder();
            geocoder.geocode({ location: latLng }, (results, status) => {
              Swal.fire({
                title: 'Atencion',
                text: 'No se encontro informacion exacta del lugar seleccionado, verificar la informacion antes de guardar',
                icon: 'warning',
              });
              if (status === 'OK') {
                for (results of results) {
                  if (results.geometry.location_type.includes('RANGE_INTERPOLATED')) {
                    getPlace(Marker, PlacesService, markerView, results.place_id, map);
                  }
                }
              }
            });
          }
        });
      })
      .catch(e => {
        // do something
      });
  };

  const fetchCategories = () => {
    const onSuccess = ({ data }) => {
      const items = data.data;
      const newCategories = items.map(item => ({ value: item?.id, label: item?.name, description: item?.description }));
      setCategories(newCategories);
    };

    const onError = ({ data }) => {
      Swal.fire(t('alertsFirm.error'), t('accepted.failed'), 'success');
    };

    getCategoriesbyType(2, onSuccess, onError);
  };

  const fetchTimezones = async () => {
    const { data, status } = await getTimezones();
    const TimeZones = data.timezones;
    setTimezones(() => {
      return TimeZones.map(item => {
        return { value: item?.name, label: item?.label };
      });
    });
  };

  const isUpdate = data => {
    if (data !== undefined) {
      reset(getEventAdapter(data));
      if (data.type === 1) {
        setValue('streetAddressTwo', data?.streetAddressTwo);
        setLat(data?.latitude);
        setLng(data?.longitude);
        setType(1);
        setPlace({
          geometry: {
            location: {
              lat: () => data?.latitude,
              lng: () => data?.longitude,
            },
          },
        });
      } else {
        onlineEvent();
      }
    }
  };

  useEffect(() => {
    setValue('type', 1);

    if (data !== null) isUpdate(data);
  }, [data, reset]);

  useEffect(() => {
    if (data === undefined) {
      setValue('timezone', Intl.DateTimeFormat().resolvedOptions().timeZone);
    }
  }, []);

  useEffect(() => {
    fetchCategories();
    initPlace();
    initMap();
    fetchTimezones();
  }, [place, type, lat, lng]);

  const onSubmit = async body => {
    const transformeTags = body.tags.reduce((uniqueTags, tag) => {
      const existingTag = uniqueTags.find(t => t.tagName === tag.label);

      if (!existingTag) {
        uniqueTags.push({ idTag: tag.value, tagName: tag.label });
      }

      return uniqueTags;
    }, []);

    if (id) {
      const { data: response, status } = await updateEvents(
        id,
        Object.assign(body, {
          idUser: user.id,
          tags: transformeTags,
          startDate: moment(body.startDate).format('YYYY-MM-DD HH:mm:ss'),
          endDate: moment(body.endDate).format('YYYY-MM-DD HH:mm:ss'),
          latitude: lat || 0,
          longitude: lng || 0,
          type: type,
          googlePlaceId: place?.place_id || '',
        }),
      );
      if (status === 200) {
        updateData(data);
        Swal.fire(t('accepted.congratulations'), t('accepted.successUpdation'), 'success');
      } else toast.error(response.message);
    } else {
      const { data: response, status } = await registerEvents(
        Object.assign(body, {
          idUser: user.id,
          tags: transformeTags,
          startDate: moment(body.startDate).format('YYYY-MM-DD HH:mm:ss'),
          endDate: moment(body.endDate).format('YYYY-MM-DD HH:mm:ss'),
          latitude: lat || 0,
          longitude: lng || 0,
          type: type,
          googlePlaceId: place?.place_id || '',
        }),
      );
      if (status === 201) {
        Swal.fire(t('accepted.congratulations'), t('accepted.success'), 'success');
        router.push('/apps/events/list/1');
      } else toast.error(response.message);
    }
  };

  return {
    handleSubmit: handleSubmit(onSubmit),
    loading,
    control,
    typeItems,
    categories,
    searchTag,
    tagsItems,
    refs,
    place,
    errors,
    venue,
    onlineEvent,
    type,
    timezones,
    isUpdate,
    handleCancel,
    cancelUpdate,
  };
}
