import addDay from 'date-fns/add_days';
import React, { Component } from 'react';
import {
  LayoutAnimation,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from 'react-native';
import { ButtonGroup, FormInput, FormLabel, FormValidationMessage } from 'react-native-elements';
import RNGooglePlaces from 'react-native-google-places';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { NavigationActions, NavigationScreenProps } from 'react-navigation';
import { connect, Dispatch } from 'react-redux';
import { OfferActions } from '../../actions';
import { Employer, Offer, OfferBody, RootState } from '../../models';
import { LocationInfo, PhotoArea } from '../common/';
import { Button, Card, Colors, Header } from '../ui';

interface StateProps {
  user: Employer;
  loading: boolean;
  error?: string;
  offer?: Offer;
}

interface DispatchProps {
  onNewOfferRequest: (data: OfferBody, photoPath?: string) => void;
  onEditOfferRequest: (data: Offer, photoPath?: string) => void;
  onEditPhotoRequest: (offerId: string, photoPath: string) => void;
  onClose: () => void;
}

interface State {
  body: OfferBody;
  photoPath: string;
  errors: {
    title?: string;
    description?: string;
    startDate?: string;
    endDate?: string;
    slots?: string;
    category?: string;
    location?: string;
  };
  selectedDateOption: 0 | 1 | 2;
}

interface OwnProps extends NavigationScreenProps<{ offer: Offer }> {
}

class NewOfferComponent extends Component<StateProps & DispatchProps & OwnProps, State> {
  scrollView?: ScrollView;
  titleInputRef?: any;
  descInputRef?: any;
  slotsInputRef?: any;
  constructor(props: StateProps & DispatchProps & OwnProps) {
    super(props);
    const now = new Date();
    this.state = {
      selectedDateOption: 0,
      photoPath: props.offer ? props.offer.image : props.user.body.avatar,
      errors: {},
      body: props.offer || {
        ownerName: props.user.body.name,
        ownerId: props.user.body.id,
        title: null,
        image: null,
        location: props.user.body.businessLocation,
        dateStart: now.getTime(),
        dateEnd: addDay(now, 1).getTime(),
        description: null,
        slots: 1,
        freeSlots: 1,
      },
    };
  }

  componentWillUpdate() {
    LayoutAnimation.easeInEaseOut();
  }

  save = () => {
    const extras: any = {};
    const hasPhoto = !!this.state.photoPath;
    const photoIsURL = hasPhoto && this.state.photoPath.startsWith('http');
    const photoPath = hasPhoto && !photoIsURL && this.state.photoPath || undefined;
    if (photoIsURL) {
      extras.photo = this.state.photoPath;
    }
    if (this.props.offer) {
      this.props.onEditOfferRequest({ ...this.props.offer, ...this.state.body },
        photoPath);
    } else {
      this.props.onNewOfferRequest({ ...this.state.body, ...extras }, photoPath);
    }
  }

  openPlacePicker = (updateOnlyLocation = false) => {
    RNGooglePlaces.openPlacePickerModal({
      country: 'PL',
    })
      .then((place) => RNGooglePlaces.lookUpPlaceByID(place.placeID))
      .then((results) => {
        const { name, address, latitude, longitude, photoUri } = results;
        this.setState({
          ...this.state,
          photoPath: photoUri || this.state.photoPath,
          body: {
            ...this.state.body,
            image: photoUri || this.state.body.image,
            location: {
              address,
              latitude,
              longitude,
              name,
            },
          },
        });
      })
      .catch((error) => console.log(error.message));
  }

  updateSelectedDateOption = (selectedDateOption) => {
    const options = {
      '0': 3,
      '1': 7,
      '2': 14,
    };

    this.setState({
      selectedDateOption,
      body: {
        ...this.state.body,
        dateEnd: addDay(this.state.body.dateStart, options[selectedDateOption.toString()]).getTime(),
      },
    });
  }

  renderSaveButton() {
    const { loading } = this.props;
    const { title, description } = this.state.body;
    const ready = title && description;
    return (
      <Button
        buttonStyle={{ height: 50 }}
        disabled={!ready}
        loading={loading}
        title={loading ? '' : this.props.offer ? 'Zapisz zmiany' : 'Dodaj ofertę'}
        onPress={!loading && this.save}
        activityIndicatorStyle={{ height: 25 }}
      />
    );
  }

  hasRequiredFields(): boolean {
    const { title, dateStart, dateEnd, slots } = this.state.body;
    return !!title && !!dateStart && !!dateEnd && !!slots;
  }

  isValid(): boolean {
    return !Object.keys(this.state.errors)
      .reduce((state, key) => state || this.state.errors[key], false);
  }

  toggleDatePicker(pickerState: any) {
    this.setState({ ...pickerState });
    if (pickerState.startPickerVisible || pickerState.endPickerVisible) {
      this.setState({
        errors: {
          ...this.state.errors,
          startDate: null,
          endDate: null,
        },
      });
    }
  }

  updateOffer(property: {}) {
    this.setState({
      body: {
        ...this.state.body,
        ...property,
      },
    });
  }

  setError(property: {}) {
    this.setState({
      errors: {
        ...this.state.errors,
        ...property,
      },
    });
  }

  updateTitle(title: string) {
    this.updateOffer({ title });
    this.setError({ title: null });
  }

  updateSlots(slots: string) {
    const num = parseInt(slots);
    this.updateOffer({ slots: num, freeSlots: num });
    this.setError({ slots: null });
  }

  validateTitle() {
    const title = this.state.body.title;
    if (!title || title.length < 5) {
      this.setError({ title: 'Napisz przynajmniej 5 znaków' });
      return;
    } else {
      this.descInputRef.focus();
    }
  }
  validateSlots() {
    const slots = this.state.body.slots;
    if (!slots || slots < 1) {
      this.setError({ slots: 'Ilość miejsc musi być większa od 0' });
      this.updateOffer({ slots: 1, freeSlots: 1 });
      return;
    }
  }

  renderLocation() {
    return (
      <LocationInfo
        location={this.state.body.location}
        onEditRequest={() => this.openPlacePicker()}
      />
    );
  }

  renderPhotoArea() {
    return (
      <PhotoArea
        photoUrl={this.state.body.image}
        onNewPath={(photoPath) => this.setState({ photoPath })}
        editable={true}
      />
    );
  }

  renderDatePickers() {
    return (
      <View>
        <Text style={{ marginHorizontal: 12, marginVertical: 6, fontWeight: 'bold' }}>
          Czas trwania oferty
        </Text>
        <ButtonGroup
          onPress={this.updateSelectedDateOption}
          selectedIndex={this.state.selectedDateOption}
          buttons={['3 dni', '7 dni', '14 dni']}
          selectedBackgroundColor={Colors.employer.primary}
          selectedButtonStyle={{ backgroundColor: Colors.employer.primary }}
          selectedTextStyle={{ color: 'white' }}
          containerStyle={{ height: 40 }}
        />
      </View>
    );
  }

  render() {
    const { body } = this.state;
    return (
      <View style={styles.container}>
        <Header title='Nowa oferta' />
        <KeyboardAwareScrollView
          extraHeight={50}
          enableOnAndroid={true}
          viewIsInsideTabBar={true}
        >
          <Card title='Szczegóły' containerStyle={{ marginHorizontal: -12 }}>
            <FormLabel>Kogo szukasz</FormLabel>
            <FormInput
              ref={(ref) => { this.titleInputRef = ref; }}
              maxLength={40}
              returnKeyType='next'
              onEndEditing={() => this.validateTitle()}
              value={body.title}
              editable={!this.props.loading}
              onChangeText={(title) => this.updateTitle(title)}
            />
            <FormValidationMessage>
              {this.state.errors.title}
            </FormValidationMessage>
            <FormLabel>Opis</FormLabel>
            <FormInput
              ref={(ref) => { this.descInputRef = ref; }}
              multiline={true}
              maxLength={1000}
              returnKeyType='next'
              value={body.description}
              editable={!this.props.loading}
              onChangeText={(description) => this.updateOffer({ description })}
            />
            <FormValidationMessage>
              {this.state.errors.description}
            </FormValidationMessage>
            <FormLabel>Ilość miejsc</FormLabel>
            <FormInput
              ref={(ref) => { this.slotsInputRef = ref; }}
              onEndEditing={() => this.validateSlots()}
              containerStyle={{ width: 60 }}
              maxLength={3}
              keyboardType='numeric'
              value={body.slots && body.slots.toString() || ''}
              editable={!this.props.loading}
              onChangeText={(slots) => this.updateSlots(slots)}
            />
            <FormValidationMessage>
              {this.state.errors.slots}
            </FormValidationMessage>
          </Card>
          {!this.props.offer && this.renderDatePickers()}
          {this.renderPhotoArea()}
          {this.renderLocation()}
        </KeyboardAwareScrollView>
        {this.renderSaveButton()}
      </View >
    );
  }
}

const mapStateToProps: (state: RootState, ownProps: OwnProps) => StateProps =
  (state, ownProps) => ({
    user: state.user as Employer,
    loading: state.network.offer.new.loading,
    error: state.network.offer.new.error,
    offer: ownProps.navigation.state.params && ownProps.navigation.state.params.offer,
  });

const mapDispatchToProps: (dispatch: Dispatch<RootState>) => DispatchProps =
  (dispatch) => ({
    onNewOfferRequest: (offer: OfferBody, photoPath?: string) =>
      dispatch(OfferActions.newOfferRequest(offer, photoPath)),
    onEditOfferRequest: (offer: Offer, photoPath?: string) =>
      dispatch(OfferActions.UpdateOfferRequest(offer, photoPath)),
    onEditPhotoRequest: (offerId: string, photoPath: string) =>
      dispatch(OfferActions.editOfferPhoto(offerId, photoPath)),
    onClose: () => dispatch(NavigationActions.back()),
  });
export const EditOffer = connect(mapStateToProps, mapDispatchToProps)(NewOfferComponent);

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  datePickersContainer: {
    flexDirection: 'row',
  },
  button: {
    marginTop: 16,
  },
  picker: {
    flex: 1,
  },
});
