import { getDistance } from 'geolib';
import { createLogic, Done } from 'redux-logic';
import { AuthActions, OfferActions } from '../actions';
import { Dispatch, Offer, RootState, UserRole } from '../models';
import { Firestore, LogicDeps, Storage } from './';

const addOfferLogic = createLogic({
  type: OfferActions.ActionKey.NEW_OFFER_REQUESTED,
  process({ action }: LogicDeps & { action: OfferActions.NewOfferRequest }, dispatch: Dispatch, done: Done) {
    const doc = Firestore.collection('offers').doc();
    const offerId = doc.id;
    const photoPath = action.photoPath;
    if (photoPath && !photoPath.startsWith('https')) {
      (Storage
        .child('offers')
        .child(offerId) as any)
        .putFile(photoPath)
        .then(({ dowloadURL }) => doc.set({ ...action.offer, image: dowloadURL, id: doc.id }))
        .then((ref) => dispatch(OfferActions.newOfferSuccess(doc.id)))
        .catch((error) => {
          return dispatch(OfferActions.newOfferFail('Failed to add offer'));
        })
        .then(() => done());
    } else {
      doc.set({ ...action.offer, id: doc.id })
        .then((ref) => dispatch(OfferActions.newOfferSuccess(doc.id)))
        .catch((error) => {
          return dispatch(OfferActions.newOfferFail('Failed to add offer'));
        })
        .then(() => done());

    }
  },
});

const editOfferPictureRequested = createLogic({
  type: OfferActions.ActionKey.EDIT_OFFER_PHOTO,
  process({ action }: LogicDeps & { action: OfferActions.EditOfferPhoto }, dispatch: Dispatch, done: Done) {
    const photoPath = action.photoPath;
    const offerId = action.offerId;

    if (photoPath) {
      (Storage
        .child('offers')
        .child(offerId) as any)
        .putFile(photoPath);
    }
  },
});

const updateOfferLogic = createLogic({
  type: OfferActions.ActionKey.UPDATE_OFFER_REQUESTED,
  process({ action }: LogicDeps & { action: OfferActions.UpdateOfferRequest }, dispatch: Dispatch, done: Done) {
    const offerId = action.offer.id;
    const doc = Firestore.collection('offers').doc(offerId);
    const photoPath = action.photoPath;
    const photoUpdated = photoPath !== action.offer.image;
    if (photoUpdated && photoPath) {
      (Storage
        .child('offers')
        .child(offerId) as any)
        .putFile(photoPath)
        .then(({ downloadURL }) => {
          return doc.update({
            ...action.offer,
            image: downloadURL,
          });
        })
        .then((ref) => dispatch(OfferActions.UpdateOfferSuccess(offerId)))
        .catch((error) => {
          return dispatch(OfferActions.UpdateOfferFail('Failed to add offer'));
        })
        .then(() => done());
    } else {
      doc.update({ ...action.offer })
        .then((ref) => dispatch(OfferActions.UpdateOfferSuccess(offerId)))
        .catch((error) => {
          return dispatch(OfferActions.UpdateOfferFail('Failed to add offer'));
        })
        .then(() => done());
    }
  },
});

const deleteOfferRequested = createLogic({
  type: OfferActions.ActionKey.DELETE_OFFER_REQUESTED,
  process({ action: { offer: { id } } }: LogicDeps & { action: OfferActions.DeleteOfferRequested },
    dispatch: Dispatch, done: Done) {
    Firestore.collection('offers').doc(id).update({
      deleted: true,
    })
      .then(() => dispatch(OfferActions.DeleteOfferSuccess(id)))
      .catch((error) => dispatch(OfferActions.DeleteOfferFail(id, error)))
      .then(() => done());
  },
});

const listenForOffers = createLogic({
  type: AuthActions.ActionKey.INITIALIZE_USER_FLOW,
  warnTimeout: 0,
  processOptions: {
    dispatchMultiple: true,
  },
  process({ action, getState }: LogicDeps & { getState: () => RootState, action: AuthActions.InitializeUserFlow },
    dispatch: Dispatch) {

    if (action.userRole === UserRole.EMPLOYER) {
      Firestore
        .collection('offers')
        .where('ownerId', '==', action.uid)
        .onSnapshot((ref) => {
          dispatch(OfferActions.EmployerOffersFetched(
            ref.docs.map((doc) => doc.data() as Offer)
              .filter((o) => !o.deleted)));
        });
    } else if (action.userRole === UserRole.EMPLOYEE) {

      Firestore
        .collection('offers')
        .where('dateEnd', '>=', Date.now())
        .onSnapshot((ref) => {
          const userLocation = getState().user.body.location;
          const offers = ref.docs.map((doc) => doc.data() as Offer)
            .map((o) => ({
              ...o,
              distance: userLocation && o.location && getDistance(userLocation, o.location, 1000, 0),
            }))
            .filter((o) => o.dateEnd > Date.now());
          dispatch(OfferActions.EmployeeOffersFetched(offers));
        });
    }
  },
});

export const offerLogic = [
  addOfferLogic,
  listenForOffers,
  updateOfferLogic,
  deleteOfferRequested,
  editOfferPictureRequested,
];
