text: /* eslint-disable max-lines-per-function */
  /* eslint-disable complexity */
  
  import React, { useState, useEffect, useRef } from 'react';
  import Link from '../../components/common/Link';
  import {
    useQueryParam,
    StringParam,
    ArrayParam,
    withDefault,
  } from 'use-query-params';
  import axios from 'axios';
  import Box from '@material-ui/core/Box';
  import CircularProgress from '@material-ui/core/CircularProgress';
  import Container from '@material-ui/core/Container';
  import Grid from '@material-ui/core/Grid';
  import Typography from '@material-ui/core/Typography';
  import { GenericHeaderSection } from '../../components';
  import { AffiliationQuestionSection } from './AffilationQuestionSection';
  import {
    OrgNameSection,
    OrganizationSelectorSection,
    OrgChange,
  } from './Organization';
  import {
    ProjectRepositorySection,
    ProjectRepositoryInput,
  } from './ProjectRepository';
  import {
    AddTopicTagSection,
    AddTagsQuestion,
    NewTags,
    CopyPasteTags,
    CurrentTopicTagSection,
  } from './TopicTagSection';
  import useTheme from '@material-ui/core/styles/useTheme';
  import BottomSection from './BottomSection';
  import StepComponent from './StepComponent';
  import { makeStyles } from '@material-ui/core/styles';
  const useStyles = makeStyles((theme) => ({
    containerPadding: {
      paddingLeft: 100,
      paddingRight: 100,
      [theme.breakpoints.down('sm')]: {
        paddingLeft: 40,
        paddingRight: 40,
      },
      [theme.breakpoints.down('xs')]: {
        padding: '0px 16px',
      },
    },
    stepGrid: {
      paddingTop: '50px',
    },
  }));
  
  /**
   * By removing matched text, we allow leeway in entering repository URL,
   * including how it might be pasted from GitHub. All these would work:
   * https://github.com/civictechindex/CTI-website-frontend.git
   * git@github.com:civictechindex/CTI-website-frontend.git
   * github.com/civictechindex/CTI-website-frontend
   * civictechindex / CTI-website-frontend
   */
  const getRepositoryUrlPath = (repositoryUrl) => {
    let result = repositoryUrl.replace(/ /g, '');
    const prefix = /^(?:https?:\/\/)?github\.com\/|git@github\.com:/;
    const suffix = /\.git$/;
    result = result.replace(prefix, '');
    result = result.replace(suffix, '');
    const arr = result.split('/');
    if (arr.length < 2) {
      result = 'error';
    } else {
      result = arr.slice(0, 2).join('/');
    }
    return result;
  };
  
  // checks if URL is deifferent
  const usePrevious = (refValue) => {
    const ref = useRef();
    useEffect(() => {
      ref.current = refValue;
    });
    return ref.current;
  };
  
  // eslint-disable-next-line max-lines-per-function
  const TagGenerator = () => {
    const theme = useTheme();
    const classes = useStyles();
    const [changeValue, setChangeValue] = useQueryParam(
      'changeValue',
      withDefault(StringParam, '')
    );
    const [currentTags, setCurrentTags] = useQueryParam(
      'currentTags',
      withDefault(ArrayParam, [])
    );
    const [displayState, setDisplayState] = useQueryParam(
      'displayState',
      withDefault(StringParam, '')
    );
    const [orgName, setOrgName] = useQueryParam(
      'orgName',
      withDefault(StringParam, '')
    );
    const [orgTags, setOrgTags] = useQueryParam(
      'orgTags',
      withDefault(ArrayParam, [])
    );
    const [repositoryName, setRepositoryName] = useQueryParam(
      'repositoryName',
      withDefault(StringParam, '')
    );
    const [repositoryUrl, setRepositoryUrl] = useQueryParam(
      'repositoryUrl',
      withDefault(StringParam, '')
    );
    const [fullRepositoryUrl, setFullRepositoryUrl] = useQueryParam(
      'fullRepositoryUrl',
      withDefault(StringParam, '')
    );
    const [tagsToAdd, setTagsToAdd] = useQueryParam(
      'tagsToAdd',
      withDefault(ArrayParam, [])
    );
    const [topicSearchError, setTopicSearchError] = useQueryParam(
      'topicSearchError',
      withDefault(StringParam, '')
    );
    const [userTags, setUserTags] = useQueryParam(
      'userTags',
      withDefault(ArrayParam, [])
    );
    const [value, setValue] = useQueryParam(
      'value',
      withDefault(StringParam, '')
    );
    const [loadingTags, setLoadingTags] = useState(false);
    const [options, setOptions] = useState([]);
    const [repoChangeAlert, setRepoChangeAlert] = useState('');
    const [displayTypo, setDisplayTypo] = useState(true);
    const breadCrumbLinks = [
      { href: '/home', name: 'Home' },
      { href: '/join-index', name: 'Add Your Project' },
    ];
  
    const resetForm = () => {
      setValue('');
      setOrgName('');
      setRepositoryUrl('');
      setRepositoryName('');
      setTopicSearchError('');
      setTagsToAdd([]);
      setCurrentTags([]);
      setUserTags([]);
      setOrgTags([]);
      setChangeValue('');
      setDisplayState('');
      setRepoChangeAlert('');
    };
  
    useEffect(() => {
      let active = true;
      axios
        .get(`${process.env.REACT_APP_API_URL}/api/organizations/`)
        .then((res) => {
          const orgs = res.data.map((org) => org.name);
          if (active) {
            setOptions(orgs);
          }
        });
      return () => {
        active = false;
      };
    }, []);
  
    useEffect(() => {
      const civicName = [];
      if (!currentTags.includes('civictechindex')) {
        civicName.push('civictechindex');
      }
      if (orgTags.length !== 0 && currentTags.length !== 0) {
        const result = orgTags.filter((ot) => !currentTags.includes(ot));
        setTagsToAdd([...civicName, ...result]);
      } else {
        setTagsToAdd([...civicName, ...orgTags]);
      }
    }, [orgTags, currentTags, setTagsToAdd]);
  
    useEffect(() => {
      if (value === 'no') {
        setOrgName('');
        setOrgTags([]);
      }
    }, [setOrgName, setOrgTags, value]);
  
    const handleEnter = (event) => {
      if (event.key === 'Enter') {
        handleSubmit();
      }
    };
  
    const handleChange = (event) => {
      setValue(event.target.value);
    };
  
    const handleChangeProjectRepository = () => {
      if (changeValue === 'TopicTag') {
        setDisplayState('TopicTag');
      } else if (changeValue === 'GenerateTags') {
        setDisplayState('GenerateTags');
      } else if (changeValue === 'CopyPasteTags') {
        setDisplayState('CopyPasteTags');
      } else {
        setChangeValue('TopicTag');
        setDisplayState('TopicTag');
      }
    };
    const prevRefUrl = usePrevious(repositoryUrl);
  
    const handleSubmit = (event) => {
      const urlPath = getRepositoryUrlPath(repositoryUrl);
      // Setting Repository Name
      const patt = /[a-z]+\//g;
      const repName = urlPath.replace(patt, '');
      setRepositoryName(repName);
      // Return error message if no url present
      if (urlPath.length === 0) {
        return setTopicSearchError('Please enter a URL');
      }
      if (urlPath === 'error') {
        return setTopicSearchError('Please enter a valid URL');
      }
      // Fetches Tags from API only if URL is changed
      if (prevRefUrl !== repositoryUrl) {
        setLoadingTags(true);
        axios
          .get('https://api.github.com/repos/' + urlPath + '/topics', {
            headers: { Accept: 'application/vnd.github.mercy-preview+json' },
          })
          .then((res) => {
            setCurrentTags(res.data.names);
            setFullRepositoryUrl('https://github.com/' + urlPath);
            setTopicSearchError('');
          })
          .catch((e) => {
            /*
             * This should store the error state.
             * Component should check for error state and resolve the correct response.
             */
            if (e) {
              setCurrentTags([]);
              setFullRepositoryUrl('');
              setTopicSearchError(
                'Cannot find repository. Please check the name and try again'
              );
              setDisplayState('ProjectUrl');
            }
          })
          .finally(() => {
            setLoadingTags(false);
          });
        if (userTags.length !== 0) {
          setRepoChangeAlert(
            'It looks like you have changed your repository, please check your tags'
          );
          setDisplayState('ChangeTags');
        } else {
          handleChangeProjectRepository();
        }
      } else if (
        topicSearchError ===
        'Cannot find repository. Please check the name and try again'
      ) {
        setDisplayState('ProjectUrl');
      } else {
        handleChangeProjectRepository();
      }
    };
  
    const handleAdd = (chip) => {
      chip = chip.toLowerCase();
      chip = chip.replace(/['`~!@#$%^&*()_|+=?;:'".<>\\{\\}\\[\]\\\\/]/gi, '');
      while (chip.startsWith('-')) {
        chip = chip.slice(1);
      }
      while (chip.endsWith('-')) {
        chip = chip.slice(0, -1);
      }
      if (chip.includes(',')) {
        let inputChipArr = chip.split(',');
        inputChipArr = inputChipArr.filter((i) => i);
        setUserTags([...new Set([...userTags, ...inputChipArr])]);
      } else setUserTags([...new Set([...userTags, chip])]);
    };
  
    const handleDelete = (deletedChip) => {
      setUserTags(userTags.filter((c) => c !== deletedChip));
    };
  
    const linkStyles = {
      fontWeight: '400',
      color: theme.palette.secondary.main,
    };
  
    const OrgProjSection = () => {
      return (
        <>
          <Grid className={classes.stepGrid}>
            <StepComponent
              step='Step 1 of 4'
              stepHeading='Select Project Affiliation'
            />
          </Grid>
          <OrgNameSection
            setDisplayState={setDisplayState}
            orgName={orgName}
            linkStyles={linkStyles}
          />
          <StepComponent step='Step 2 of 4' stepHeading='Find Project' />
          <ProjectRepositorySection
            repositoryUrl={fullRepositoryUrl}
            setDisplayState={setDisplayState}
            linkStyles={linkStyles}
          />
        </>
      );
    };
  
    const RadioYes = ({ value, setOrgName }) => {
      return (
        <Grid container id='container-affiliated'>
          <OrganizationSelectorSection
            orgName={orgName}
            setOrgName={setOrgName}
            options={options}
            setOptions={setOptions}
          />
          <OrgChange
            value={value}
            orgName={orgName}
            setOrgName={setOrgName}
            setOrgTags={setOrgTags}
            changeValue={changeValue}
            setDisplayState={setDisplayState}
            linkStyles={linkStyles}
          />
        </Grid>
      );
    };
  
    // eslint-disable-next-line complexity
    const renderCurrentState = () => {
      switch (displayState) {
      case 'ProjectUrl':
        return (
          <>
            <Grid className={classes.stepGrid}>
              <StepComponent
                step='Step 1 of 4'
                stepHeading='Select Project Affiliation'
              />
            </Grid>
            <OrgNameSection
              setDisplayState={setDisplayState}
              orgName={orgName}
              linkStyles={linkStyles}
            />
            <StepComponent step='Step 2 of 4' stepHeading='Find Project' />
            <ProjectRepositoryInput
              repositoryUrl={repositoryUrl}
              handleEnter={handleEnter}
              setRepositoryUrl={setRepositoryUrl}
              topicSearchError={topicSearchError}
              setTopicSearchError={setTopicSearchError}
              handleSubmit={handleSubmit}
            />
          </>
        );
      case 'TopicTag':
        return (
          <>
            <OrgProjSection />
            {loadingTags ? (
              <Box display='flex' alignItems='center' justifyContent='center'>
                <CircularProgress />
              </Box>
            ) : (
              <>
                <CurrentTopicTagSection
                  currentTags={currentTags}
                  repositoryName={repositoryName}
                />
                <StepComponent
                  step='Step 3 of 4'
                  stepHeading='Create Topic Tags'
                />
                <AddTagsQuestion
                  userTags={userTags}
                  displayState={displayState}
                  setDisplayState={setDisplayState}
                  changeValue={changeValue}
                  setChangeValue={setChangeValue}
                  resetForm={resetForm}
                  handleAdd={handleAdd}
                  handleDelete={handleDelete}
                  repoChangeAlert={repoChangeAlert}
                  setRepoChangeAlert={setRepoChangeAlert}
                  displayTypo={displayTypo}
                  setDisplayTypo={setDisplayTypo}
                />
              </>
            )}
          </>
        );
      case 'GenerateTags':
        return (
          <>
            <OrgProjSection />
            <StepComponent step='Step 3 of 4' stepHeading='Create Topic Tags' />
            <CurrentTopicTagSection
              currentTags={currentTags}
              repositoryName={repositoryName}
            />
            <NewTags
              tagsToAdd={tagsToAdd}
              setDisplayState={setDisplayState}
              setChangeValue={setChangeValue}
              resetForm={resetForm}
              linkStyles={linkStyles}
              userTags={userTags}
              setUserTags={setUserTags}
              handleAdd={handleAdd}
              handleDelete={handleDelete}
              displayTypo={displayTypo}
            />
          </>
        );
      case 'ChangeTags':
        return (
          <>
            <OrgProjSection />
            <StepComponent step='Step 3 of 4' stepHeading='Create Topic Tags' />
            <CurrentTopicTagSection
              currentTags={currentTags}
              repositoryName={repositoryName}
            />
            <AddTopicTagSection
              userTags={userTags}
              displayState={displayState}
              setDisplayState={setDisplayState}
              changeValue={changeValue}
              setChangeValue={setChangeValue}
              resetForm={resetForm}
              handleAdd={handleAdd}
              handleDelete={handleDelete}
              repoChangeAlert={repoChangeAlert}
              setRepoChangeAlert={setRepoChangeAlert}
            />
          </>
        );
      case 'CopyPasteTags':
        return (
          <>
            <OrgProjSection />
            <StepComponent step='Step 3 of 4' stepHeading='Create Topic Tags' />
            <CurrentTopicTagSection
              currentTags={currentTags}
              repositoryName={repositoryName}
            />
            <CopyPasteTags
              tagsToAdd={tagsToAdd}
              setDisplayState={setDisplayState}
              userTags={userTags}
              repositoryName={repositoryName}
              repositoryUrl={fullRepositoryUrl}
              linkStyles={linkStyles}
            />
          </>
        );
      default:
        return (
          <>
            <Grid className={classes.stepGrid}>
              <StepComponent
                step='Step 1 of 4'
                stepHeading='Select Project Affiliation'
              />
            </Grid>
            <AffiliationQuestionSection value={value} handleChange={handleChange}>
              <Typography variant='body1'>
                Are you affiliated with an&nbsp;
                <Link to='/organizations'>organization</Link>?
              </Typography>
            </AffiliationQuestionSection>
            {value === 'yes' ? (
              <RadioYes value={value} setOrgName={setOrgName} />
            ) : null}
            {value === 'no' ? (
              <OrgChange
                value={value}
                orgName={orgName}
                setOrgName={setOrgName}
                setOrgTags={setOrgTags}
                changeValue={changeValue}
                setDisplayState={setDisplayState}
              />
            ) : null}
          </>
        );
      }
    };
  
    return (
      <Box>
        <Box className='boxBackground'>
          <Container className='containerDefault'>
            <GenericHeaderSection
              mainTitle='Tag Generator'
              breadCrumbLinks={breadCrumbLinks}
            >
              <Typography className='genSubheadTypo'>
                Join the Civic Tech Index by submitting your open-source project.
                <br /> This process takes less than one minute to complete.
              </Typography>
            </GenericHeaderSection>
          </Container>
        </Box>
        <Box className='containerGray' style={{ paddingBottom: '30px' }}>
          <Container className={classes.containerPadding}>
            {renderCurrentState()}
          </Container>
        </Box>
        {displayState === 'CopyPasteTags' ? <BottomSection /> : null}
      </Box>
    );
  };
  
  export default TagGenerator;
  