import React, { useRef, useEffect, useLayoutEffect, useState, useReducer } from 'react';
import { Card, CardBody, Col, Row, CardHeader, Form, FormGroup, Label, Input } from 'reactstrap';
import Select from 'react-select';
import FalconCardHeader from '../common/FalconCardHeader';
import { useTranslation } from 'react-i18next';
import JKProfileAvatar from '../profile/JKProfileAvatar';
import { useAuth } from '../../context/UserAuth';
import { useForm, Controller } from 'react-hook-form';
import { getInstruments, getGenres, updateUser, getCountries, getRegions, getCities } from '../../helpers/rest';
import JKProfileAvatarUpload from '../profile/JKProfileAvatarUpload';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Prompt } from 'react-router';
import { useAppData } from '../../context/AppDataContext';

function JKEditProfile() {
  const { t } = useTranslation('profile');
  const { currentUser } = useAuth();

  const [musicInstruments, setMusicInstruments] = useState([]);
  const [userMusicInstruments, setUserMusicInstruments] = useState([]);
  const [userMusicInstrumentsReceived, setUserMusicInstrumentsReceived] = useState(false);

  const [genres, setGenres] = useState([]);
  const [userGenres, setUserGenres] = useState([]);
  const [userGenresReceived, setUserGenresReceived] = useState(false);

  const [instrumentsInitialLoadingDone, setInstrumentsInitialLoadingDone] = useState(false);
  const [genreInitialLoadingDone, setGenreInitialLoadingDone] = useState(false);

  const [countries, setCountries] = useState([]);
  const [regions, setRegions] = useState([]);
  const [cities, setCities] = useState([]);
  const [showAvatarUpload, setShowAvatarUpload] = useState(false);
  const [updating, setUpdating] = useState(false);

  // const { userProfile, photoUrl } = useUserProfile(currentUser);
  const { appData } = useAppData();
  const { currentUserPhotoUrl, userProfile } = appData;

  const [_, forceUpdate] = useReducer(x => x + 1, 0);

  const saveTimeoutRef = useRef(null);
  const cityRef = useRef(null);
  const regionRef = useRef(null);

  const PROFICIENCIES = [
    { value: '1', label: t('profeciency.beginner') },
    { value: '2', label: t('profeciency.intermediate') },
    { value: '3', label: t('profeciency.advanced') }
  ];

  const { register, control, handleSubmit, setValue, getValues, isDirty } = useForm({
    defaultValues: {
      firstName: '',
      lastName: '',
      country: '',
      state: '',
      city: '',
      biography: '',
      subscribeEmail: false,
      virtualBand: false,
      traditionalBand: false,
      cowriting: false,
      instruments: [],
      genres: []
    }
  });

  useEffect(() => {
    if (!userProfile || Object.keys(userProfile).length === 0) return;
    updateFormData(userProfile);
    setUserGenres(userProfile.genres.filter(genre => genre.genre_type && genre.genre_type === 'profile'));
    setUserGenresReceived(true);
    setUserMusicInstruments(userProfile.instruments);
    setUserMusicInstrumentsReceived(true);
  }, [userProfile]);

  useLayoutEffect(() => {
    fetchInstruments();
    fetchGenres();
    fetchCountries();
  }, []);

  const updateFormData = data => {
    setValue('firstName', data.first_name);
    setValue('lastName', data.last_name);
    setValue('country', data.country ? data.country : '');
    setValue('state', data.state ? data.state : '');
    setValue('city', data.city ? data.city : '');
    setValue('biography', data.biography);
    setValue('subscribeEmail', data.subscribe_email);
    setValue('virtualBand', data.virtual_band);
    setValue('traditionalBand', data.traditional_band);
    setValue('cowriting', data.cowriting);
    setValue('instruments', data.instruments);
    setValue('genres', data.genres.filter(genre => genre.genre_type && genre.genre_type === 'profile'));
    if (data.country) {
      fetchRegions(data.country);
    }
    if (data.country && data.state) {
      fetchCities(data.country, data.state);
    }
  };

  const fetchInstruments = () => {
    getInstruments()
      .then(response => {
        if (response.ok) {
          return response.json();
        }
      })
      .then(data => {
        setMusicInstruments(data);
      })
      .catch(error => console.log(error));
  };

  useEffect(() => {
    if (instrumentsInitialLoadingDone || musicInstruments.length === 0 || !userMusicInstrumentsReceived) return;

    const updatedMusicInstruments = musicInstruments.map(musicInstrument => {
      const instrument = getValues('instruments').find(instrument => instrument.instrument_id === musicInstrument.id);

      if (instrument) {
        musicInstrument.proficiency_level = instrument.proficiency_level;
        musicInstrument.priority = instrument.priority;
        musicInstrument.checked = true;
        musicInstrument.instrument_id = instrument.instrument_id;
      } else {
        musicInstrument.proficiency_level = null;
        musicInstrument.priority = '0'; // default priority - to prevent database not null constraint violation
        musicInstrument.checked = false;
        musicInstrument.instrument_id = null;
      }
      return musicInstrument;
    });
    setMusicInstruments(updatedMusicInstruments);
    setInstrumentsInitialLoadingDone(true);
  }, [userMusicInstrumentsReceived, musicInstruments]);

  const fetchGenres = () => {
    getGenres()
      .then(response => {
        if (response.ok) {
          return response.json();
        }
      })
      .then(data => {
        setGenres(data);
      })
      .catch(error => {
        console.log(error);
      });
  };

  useEffect(() => {
    if (genreInitialLoadingDone || genres.length === 0 || !userGenresReceived) return;

    const updatedGenres = genres.map(genre => {
      const userGenre = userGenres.find(userGenre => userGenre.genre_id === genre.id);
      if (userGenre) {
        genre.checked = true;
      } else {
        genre.checked = false;
      }
      genre.genre_id = genre.id;
      return genre;
    });
    setGenres(updatedGenres);
    setGenreInitialLoadingDone(true);
  }, [userGenresReceived, genres]);

  const fetchCountries = () => {
    getCountries()
      .then(response => {
        if (response.ok) {
          return response.json();
        }
      })
      .then(data => {
        setCountries(data.countriesx);
      })
      .catch(error => console.log(error));
  };

  const fetchRegions = countryCode => {
    getRegions(countryCode)
      .then(response => {
        if (response.ok) {
          return response.json();
        }
      })
      .then(data => {
        setRegions(data.regions);
        skipRegionChange.current = false;
      })
      .catch(error => console.log(error));
  };

  const fetchCities = (country, region) => {
    getCities(country, region)
      .then(response => {
        if (response.ok) {
          return response.json();
        }
      })
      .then(data => {
        setCities(data.cities);
      })
      .catch(error => console.log(error));
  };

  const onSubmit = data => console.log(data);

  const handleInstrumentSelect = (e, musicInstrument) => {
    if (e.target.checked) {
      const userInstruments = getValues('instruments');
      const thisInstrument = userInstruments.find(
        instrument => instrument.instrument_id === musicInstrument.instrument_id
      );
      if (thisInstrument) return;
      const { id } = musicInstrument;
      const updatedInstruments = [...userInstruments, { ...musicInstrument, instrument_id: id }];
      setValue('instruments', updatedInstruments);
    } else {
      const updatedInstruments = getValues('instruments').filter(
        instrument => instrument.instrument_id !== musicInstrument.instrument_id
      );
      setValue('instruments', updatedInstruments);
    }

    const updatedMusicInstruments = musicInstruments.map(instrument => {
      if (instrument.id === musicInstrument.id) {
        instrument.checked = e.target.checked;
      } else {
        instrument.checked = instrument.checked;
      }
      return instrument;
    });

    setMusicInstruments(updatedMusicInstruments);
    handleChange();
  };

  const handleInstrumentProficiencyChange = (option, musicInstrument) => {
    let updatedInstruments = [];
    const userInstrument = getValues('instruments').find(instrument => instrument.instrument_id === musicInstrument.id);
    if (!userInstrument) {
      updatedInstruments = [...getValues('instruments'), { ...musicInstrument, proficiency_level: option.value }];
      //setValue('instruments', updatedInstruments);
    } else {
      updatedInstruments = getValues('instruments').map(instrument => {
        if (instrument.instrument_id === musicInstrument.id) {
          instrument.proficiency_level = option.value;
        }
        return instrument;
      });
      //setValue('instruments', updatedInstruments);
    }
    setValue('instruments', updatedInstruments);

    const updatedMusicInstruments = musicInstruments.map(instrument => {
      if (instrument.id === musicInstrument.id) {
        instrument.proficiency_level = option.value;
      }
      return instrument;
    });

    setMusicInstruments(updatedMusicInstruments);

    //forceUpdate();
    handleChange();
  };

  const handleGenreChange = (e, genre) => {
   
    if (e.target.checked) {
      const userGenres = getValues('genres');
      const thisGenre = userGenres.find(userGenre => userGenre.genre_id === genre.genre_id);
      if (thisGenre) return;
      const updatedGenres = [...userGenres, { ...genre }];
      setValue('genres', updatedGenres);
    } else {
      const updatedGenres = getValues('genres').filter(userGenre => userGenre.genre_id !== genre.genre_id);
      setValue('genres', updatedGenres);
    }

    const updatedGenres = genres.map(genreItem => {
      console.log('genreItem', genreItem, genre);
      if (genreItem.genre_id === genre.genre_id) {
        genreItem.checked = e.target.checked;
      } else {
        genreItem.checked = genreItem.checked;
      }
      return genreItem;
    });

    setGenres(updatedGenres);
    handleChange();
  };

  const handleTextInputChage = () => {
    setUpdating(true);
    clearTimeout(saveTimeoutRef.current);
    saveTimeoutRef.current = setTimeout(() => {
      handleChange();
    }, 2000);
  };

  const skipRegionChange = useRef(false);

  const handleCountryChange = selectedOpt => {
    const country = selectedOpt.value;
    setValue('country', country);
    setValue('state', null);
    setValue('city', null);
    setRegions([]);
    skipRegionChange.current = true;
    regionRef.current.select.clearValue();
    setCities([]);
    cityRef.current.select.clearValue();
    fetchRegions(country);
    forceUpdate();
    handleChange();
  };

  const handleRegionChange = selectedOpt => {
    if (!selectedOpt) return;

    if (skipRegionChange.current) {
      skipRegionChange.current = false;
      return;
    }

    const state = selectedOpt.value;
    const country = getValues('country');
    setValue('state', state);
    setValue('city', '');
    setCities([]);
    cityRef.current.select.clearValue();
    fetchCities(country, state);
    handleChange();
  };

  const handleCityChange = selectedOpt => {
    if (!selectedOpt) return;
    const city = selectedOpt.value;
    setValue('city', city);
    handleChange();
  };

  const handleChange = () => {
    const params = getValues();
    const uniqueGenres = [...new Set(params.genres.map(genre => genre.genre_id))];
    const data = {
      first_name: params.firstName,
      last_name: params.lastName,
      country: params.country,
      state: params.state,
      city: params.city,
      biography: params.biography,
      subscribe_email: params.subscribeEmail,
      virtual_band: params.virtualBand,
      traditional_band: params.traditionalBand,
      cowriting: params.cowriting,
      instruments: params.instruments,
      genres: uniqueGenres
    };

    const instrments = params.instruments.filter(
      instrument => instrument.instrument_id !== null && instrument.proficiency_level !== null
    );

    data.instruments = instrments;

    setUpdating(true);
    updateUser(currentUser.id, data)
      .then(response => {
        if (response.ok) {
          console.log('User data updated');
        } else {
          console.log('Error updating user data');
        }
      })
      .catch(error => console.log(error))
      .finally(() => {
        setUpdating(false);
      });
  };

  useEffect(() => {
    function beforeUnload(e) {
      if (updating) e.preventDefault();
    }

    window.addEventListener('beforeunload', beforeUnload);

    return () => {
      window.removeEventListener('beforeunload', beforeUnload);
    };
  }, [updating]);

  const toggleAvatarUpload = () => {
    setShowAvatarUpload(!showAvatarUpload);
  };

  return (
    <>
      <Prompt when={updating} message="The changes are being saved. Are you sure you want to leave?" />
      <Card>
        <FalconCardHeader title={t('page_title', { ns: 'profile' })} titleClass="font-weight-bold">
          {updating && (
            <>
              <FontAwesomeIcon icon="spinner" spin className="ml-2" /> <span>updating...</span>
            </>
          )}
        </FalconCardHeader>
        <CardBody className="pt-3" style={{ backgroundColor: '#edf2f9' }}>
          <Form data-testid="edit_profile_form">
            <Row>
              <Col sm="12" md="6">
                <Card>
                  <CardHeader>
                    <h5>{t('basics')}</h5>
                  </CardHeader>
                  <CardBody className="bg-light">
                    <Row>
                      <Col md={4}>
                        <FormGroup>
                          <Label for="firstName">{t('first_name')}</Label>
                          <Controller
                            name="firstName"
                            control={control}
                            render={({ field: { onChange, value } }) => (
                              <Input
                                data-testid="firstName"
                                value={value}
                                onChange={e => {
                                  onChange(e);
                                  handleTextInputChage();
                                }}
                              />
                            )}
                          />
                        </FormGroup>
                      </Col>
                      <Col md={4}>
                        <FormGroup>
                          <Label for="lastName">{t('last_name')}</Label>
                          <Controller
                            name="lastName"
                            control={control}
                            render={({ field: { onChange, value } }) => (
                              <Input
                                data-testid="lastName"
                                value={value}
                                onChange={e => {
                                  onChange(e);
                                  handleTextInputChage();
                                }}
                              />
                            )}
                          />
                        </FormGroup>
                      </Col>
                      <Col md={4} className="d-flex flex-column">
                        <a
                          href="#"
                          onClick={e => {
                            e.preventDefault();
                            toggleAvatarUpload();
                          }}
                          style={{ marginTop: 'auto', marginBottom: 'auto' }}
                        >
                          <div className="d-flex align-items-center">
                            <div>{<JKProfileAvatar src={currentUserPhotoUrl} size="3xl" />}</div>
                            <div>
                              <FontAwesomeIcon icon={['fas', 'edit']} className="ml-2 mr-1" />
                            </div>
                          </div>
                        </a>
                      </Col>
                    </Row>
                    <Row>
                      <Col md={4}>
                        <FormGroup>
                          <Label for="country">{t('country')}</Label>
                          {countries.length > 0 && (
                            <Controller
                              name="country"
                              control={control}
                              render={({ field: { onChange, value } }) => {
                                const country = countries.find(country => country.countrycode === value);
                                if (!country) {
                                  return (
                                    <Select
                                      data-testid="countrySelect"
                                      onChange={handleCountryChange}
                                      options={countries.map(c => {
                                        return { value: c.countrycode, label: c.countryname };
                                      })}
                                    />
                                  );
                                }
                                return (
                                  <Select
                                    data-testid="countrySelect"
                                    value={{ value: country.countrycode, label: country.countryname }}
                                    onChange={handleCountryChange}
                                    options={countries.map(c => {
                                      return { value: c.countrycode, label: c.countryname };
                                    })}
                                  />
                                );
                              }}
                            />
                          )}
                        </FormGroup>
                      </Col>
                      <Col md={4}>
                        <FormGroup>
                          <Label for="state">{t('state')}</Label>

                          <Controller
                            name="state"
                            control={control}
                            render={({ field: { onChange, value } }) => {
                              const region = regions.find(region => region.region === value);
                              if (region) {
                                return (
                                  <Select
                                    isDisabled={getValues('country') === null || regions.length === 0}
                                    value={{ value: region.region, label: region.name }}
                                    ref={regionRef}
                                    onChange={handleRegionChange}
                                    options={regions.map(r => {
                                      return { value: r.region, label: r.name };
                                    })}
                                  />
                                );
                              } else {
                                return (
                                  <Select
                                    isDisabled={getValues('country') === null || regions.length === 0}
                                    ref={regionRef}
                                    onChange={handleRegionChange}
                                    options={regions.map(r => {
                                      return { value: r.region, label: r.name };
                                    })}
                                  />
                                );
                              }
                            }}
                          />
                        </FormGroup>
                      </Col>
                      <Col md={4}>
                        <FormGroup>
                          <Label for="city">{t('city')}</Label>
                          <Controller
                            name="city"
                            control={control}
                            render={({ field: { onChange, value } }) => (
                              <Select
                                isDisabled={getValues('region') === null || cities.length === 0}
                                value={{ value: value, label: value }}
                                ref={cityRef}
                                onChange={handleCityChange}
                                options={cities.map(c => {
                                  return { value: c, label: c };
                                })}
                              />
                            )}
                          />
                        </FormGroup>
                      </Col>
                    </Row>
                    <FormGroup>
                      <Label for="biography">{t('musical_biography')}</Label>
                      <Controller
                        name="biography"
                        control={control}
                        render={({ field: { onChange, value } }) => (
                          <Input
                            data-testid="biography"
                            style={{ height: 200 }}
                            type="textarea"
                            value={value ? value : ''}
                            onChange={e => {
                              onChange(e);
                              handleTextInputChage();
                            }}
                          />
                        )}
                      />
                    </FormGroup>
                    <FormGroup check>
                      <Controller
                        name="subscribeEmail"
                        control={control}
                        render={({ field: { onChange, value } }) => (
                          <Input
                            data-testid="subscribeEmail"
                            checked={value}
                            type="checkbox"
                            onChange={e => {
                              onChange(e);
                              handleChange();
                            }}
                          />
                        )}
                      />
                      <Label check for="subscribeEmail">
                        {t('accept_emails')}
                      </Label>
                    </FormGroup>
                  </CardBody>
                </Card>

                <Card className="mt-3">
                  <CardHeader>
                    <h5>{t('interests')}</h5>
                  </CardHeader>
                  <CardBody className="bg-light">
                    <FormGroup check>
                      <Controller
                        name="virtualBand"
                        control={control}
                        render={({ field: { onChange, value } }) => (
                          <Input
                            data-testid="virtualBand"
                            checked={value}
                            onChange={e => {
                              onChange(e);
                              handleChange();
                            }}
                            type="checkbox"
                          />
                        )}
                      />
                      <Label check for="check">
                        {t('interest_joining_virtual_band')}
                      </Label>
                    </FormGroup>
                    <FormGroup check>
                      <Controller
                        name="traditionalBand"
                        control={control}
                        render={({ field: { onChange, value } }) => (
                          <Input
                            data-testid="traditionalBand"
                            checked={value}
                            onChange={e => {
                              onChange(e);
                              handleChange();
                            }}
                            type="checkbox"
                          />
                        )}
                      />
                      <Label check for="check">
                        {t('interest_joining_in_person_band')}
                      </Label>
                    </FormGroup>
                    <FormGroup check>
                      <Controller
                        name="cowriting"
                        control={control}
                        render={({ field: { onChange, value } }) => (
                          <Input
                            data-testid="cowriting"
                            checked={value}
                            onChange={e => {
                              onChange(e);
                              handleChange();
                            }}
                            type="checkbox"
                          />
                        )}
                      />
                      <Label check for="check">
                        {t('interest_cowriting_songs')}
                      </Label>
                    </FormGroup>
                  </CardBody>
                </Card>
              </Col>
              <Col sm="12" md="6">
              <Card className="mt-3  mt-md-0">
                  <CardHeader>
                    <h5>{t('instruments')}</h5>
                  </CardHeader>
                  <CardBody data-testid="instruments" className="bg-light" style={{ overflowY: 'scroll', height: 300 }}>
                    <FormGroup check>
                      {musicInstruments.map(musicInstrument => {
                        return (
                          <Row key={musicInstrument.id} className="mb-1">
                            <Col md={5}>
                              <Input
                                onChange={e => {
                                  handleInstrumentSelect(e, musicInstrument);
                                }}
                                type="checkbox"
                                checked={musicInstrument.checked}
                              />

                              <Label check for="check">
                                {musicInstrument.description}
                              </Label>
                            </Col>
                            <Col md={7}>
                              <Select
                                value={
                                  musicInstrument.checked
                                    ? PROFICIENCIES.find(p => parseInt(p.value) === musicInstrument.proficiency_level)
                                    : null
                                }
                                onChange={e => {
                                  handleInstrumentProficiencyChange(e, musicInstrument);
                                }}
                                options={PROFICIENCIES}
                                isDisabled={!musicInstrument.checked}
                              />
                            </Col>
                          </Row>
                        );
                      })}
                    </FormGroup>
                  </CardBody>
                </Card>
                <Card className="mt-3">
                  <CardHeader>
                    <h5>{t('genres')}</h5>
                  </CardHeader>
                  <CardBody data-testid="genres" className="bg-light" style={{ overflowY: 'scroll', height: 300 }}>
                    <FormGroup check>
                      {genres.map(genre => {
                        return (
                          <Row key={genre.genre_id}>
                            <Col md={4}>
                              <Input
                                onChange={e => {
                                  handleGenreChange(e, genre);
                                }}
                                type="checkbox"
                                checked={genre.checked}
                              />
                              <Label check for="check">
                                {genre.description}
                              </Label>
                            </Col>
                          </Row>
                        );
                      })}
                    </FormGroup>
                  </CardBody>
                </Card>
            
              </Col>
            </Row>
          </Form>
        </CardBody>
      </Card>
      <JKProfileAvatarUpload show={showAvatarUpload} toggle={toggleAvatarUpload} />
    </>
  );
}

export default JKEditProfile;
