import React, { useState, useEffect } from 'react';
import { useLocation, Link } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import queryString from 'query-string';
import { SERVER_URL } from '../constants';
import InputWithLabel from './InputWithLabel';
import Table from './Table';
import styled, { createGlobalStyle } from 'styled-components';
import axios from 'axios';
import { ToastContainer, toast, Slide } from 'react-toastify';
import { DeleteIcon } from '../icons';

const GlobalStyle = createGlobalStyle`
  body {
    text-align: center;
    padding: 2em;
    background: #000;
    color: #fff;
    border: 1em solid;
    border-image: linear-gradient(90deg, rgb(64,224,208), rgb(255,140,0), rgb(255,0,128) ) 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  button,
  input {
    appearance: none;
    border: 0;
  }
  .Toastify__toast--info {
    background: #2cce9f;
    border-radius: 8px;
    color: #000;
    margin: 2em;
    font: inherit;
  }
  .Toastify__close-button {
    color: #000;
  }
`;

const ErrorText = styled.p`
  color: red;
  font-size: 0.8rem;
`;

const handleKeyUp = ({
  e,
  initialDecks,
  setFilteredDecks,
  setPublicDecksInputVal,
}) => {
  if (initialDecks.length) {
    if (e.target.value.trim() === '') {
      setFilteredDecks([]);
      setPublicDecksInputVal(false);
      return;
    }
    if (e.target.value !== '') {
      setPublicDecksInputVal(true);
    }
    const result = initialDecks.filter(({ name }) =>
      name.startsWith(e.target.value.toLowerCase().trim())
    );

    setFilteredDecks(result);
  }
};

const getCardsLength = ({ type, deckTable }) => {
  if (!deckTable && !deckTable.length) {
    return <GreenText>0</GreenText>;
  }

  const cardLength = deckTable.filter((card) => card.type === type).length;
  return (
    <>
      <GreenText>{cardLength}</GreenText>
      {` ${type} card${cardLength !== 1 ? 's' : ''}`}
    </>
  );
};

const addCard = ({
  e,
  setIsLoading,
  deckTable,
  type,
  text,
  setDeckTable,
  location,
  setError,
  setWhiteCard,
  setBlackCard,
  defaultLocation,
  reactGA,
}) => {
  e.preventDefault();

  if (!text.trim().length) {
    return setError(
      'Please enter something, you know, more than 0 characters.'
    );
  }

  // if text already exists in the deck, return error
  if (
    deckTable.find(
      (card) =>
        card.type === type && card.text.toLowerCase() === text.toLowerCase()
    )
  ) {
    return setError(
      `This same ${type} card has already been submitted. Please try again.`
    );
  }

  setIsLoading(true);
  const deckName = location.replace('/', '');
  const secret = queryString.parse(defaultLocation.search).secret;
  axios
    .post(`${SERVER_URL}/api/addCard/`, { type, text, deckName, secret })
    .then((res) => {
      // if successful, update state
      // const data = cleanUpData(res.data);
      // setDeckTable(data);
      if (res.data.includes('Error')) {
        return setError(res.data);
      }

      setDeckTable((deckTable) => [...deckTable, { type, text }]);
      setError('');

      reactGA.event({
        category: 'Deck',
        action: `Added a ${type} card to the ${deckName} deck`,
        label: text,
      });

      if (type === 'black') {
        setBlackCard('');
      } else {
        setWhiteCard('');
      }
    })
    .catch((err) => setError(err))
    .finally((info) => {
      setIsLoading(false);
    });
};

const deleteCard = ({
  e,
  type,
  text,
  setDeckTable,
  location,
  setError,
  setIsDeleting,
  defaultLocation,
  reactGA, }) => {

  e.preventDefault();

  setIsDeleting(true);

  const confirmed = window && window.confirm(`Are you sure you want to delete the ${type} card "${text}" from your deck?`);

  if (!confirmed) {
    return setIsDeleting(false);
  }

  const deckName = location.replace('/', '');
  const secret = queryString.parse(defaultLocation.search).secret;

  axios
    .post(`${SERVER_URL}/api/deleteCard/`, { type, text, deckName, secret })
    .then((res) => {
      // if successful, update state
      if (res.data.includes('Error')) {
        return setError(res.data);
      }

      setDeckTable(deckTable => {
        const newDeckTable = [...deckTable];
        const cardToRemoveIndex = newDeckTable.findIndex(card => card.text === text);
        newDeckTable.splice(cardToRemoveIndex, 1);

        return newDeckTable;
      });
      setError('');

      reactGA.event({
        category: 'Deck',
        action: `Removed a ${type} card from the ${deckName} deck`,
        label: text,
      });
    })
    .catch((err) => setError(err))
    .finally((info) => {
      setIsDeleting(false);
    });
}

const Title = ({ location }) => {
  if (location && location !== '/') {
    return (
      <MainHeading>
        Add cards to the{' '}
        <NameOfDeck>{location.replace(/\/|-/g, ' ')}</NameOfDeck> deck
      </MainHeading>
    );
  } else {
    return <MainHeading>Edit a deck</MainHeading>;
  }
};

const EditADeck = ({ title, reactGA }) => {
  const [whiteCard, setWhiteCard] = useState('');
  const [blackCard, setBlackCard] = useState('');
  const [initialDecks, setInitialDecks] = useState([]);
  const [filteredDecks, setFilteredDecks] = useState([]);
  const [deckTable, setDeckTable] = useState([]);
  const [deckExists, setDeckExists] = useState('');
  const [error, setError] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [isDeleting, setIsDeleting] = useState(false);
  const [publicDecksInputVal, setPublicDecksInputVal] = useState(false);
  const defaultLocation = useLocation();
  const location = defaultLocation.pathname.replace('/edit-deck', '');

  useEffect(() => {
    // If we haven't chosen a deck and are just hitting the "/edit-deck" page
    if (!location || location === '/') {
      axios.get(`${SERVER_URL}/api/getPublicDecks`).then((res) => {
        console.log(res.data);
        setInitialDecks(res.data);
      });
    } else {
      const secret = queryString.parse(defaultLocation.search).secret;
      async function checkSecret() {
        try {
          // check for the deck secret first
          await axios.post(`${SERVER_URL}/api/getDeckSecret`, {
            secret,
            deckName: location.replace('/', ''),
          });
          // if secret is legit, keep going and get cards from the deck
          axios
            .get(`${SERVER_URL}/api/getCardsFromDeck${location}`)
            .then((res) => {
              if (res.data === 'no result') {
                return setDeckExists('no result');
              }
              if (!secret) {
                return setError(
                  "You don't have permissions to edit this deck."
                );
              }
              if (res.data.includes('Error')) {
                return setError(res.data);
              }
              setDeckTable(res.data);
              setDeckExists('result found');
              // Pop a success toast
              toast.info(
                'Note: Bookmark or save this page. You can only update this deck with this exact link. Only send to people you trust.',
                {
                  toastId: 'copy-link-info',
                  position: toast.POSITION.TOP_CENTER,
                }
              );
            });
        } catch (err) {
          return setError(err.response.data);
        }
      }
      checkSecret();
    }
  }, [location, defaultLocation]);
  return (
    <Page>
      <GlobalStyle />
      <Helmet>
        <title>{title}</title>
      </Helmet>
      <Title location={location} />

      {location && location !== '/' ? (
        <>
          {deckExists === 'result found' ? (
            <>
              <p>
                <em>
                  This deck has {getCardsLength({ type: 'white', deckTable })} and{' '}
                  {getCardsLength({ type: 'black', deckTable })}
                </em>
              </p>

              <Form
                onSubmit={(e) =>
                  addCard({
                    e,
                    setIsLoading,
                    deckTable,
                    type: 'white',
                    text: whiteCard,
                    initialDecks,
                    setFilteredDecks,
                    setDeckTable,
                    location,
                    setError,
                    setWhiteCard,
                    defaultLocation,
                    reactGA,
                  })
                }
              >
                <InputWithLabel
                  type="white"
                  whiteCard={whiteCard}
                  buttonText="ADD WHITE CARD"
                  labelText="Add a White Card"
                  onChange={setWhiteCard}
                  placeholderText="e.g. Spontaneous combustion"
                  isLoading={isLoading}
                />
              </Form>
              {error && error.includes('white') && (
                <ErrorText>{error}</ErrorText>
              )}

              <Form
                onSubmit={(e) =>
                  addCard({
                    e,
                    setIsLoading,
                    deckTable,
                    type: 'black',
                    text: blackCard,
                    initialDecks,
                    setFilteredDecks,
                    setDeckTable,
                    location,
                    setError,
                    setBlackCard,
                    defaultLocation,
                    reactGA,
                  })
                }
              >
                <InputWithLabel
                  type="black"
                  blackCard={blackCard}
                  buttonText="ADD BLACK CARD"
                  labelText="Add a Black Card"
                  onChange={setBlackCard}
                  placeholderText="e.g. Abraham Lincoln once said _______."
                  isLoading={isLoading}
                />
              </Form>
              {error && error.includes('black') && (
                <ErrorText>{error}</ErrorText>
              )}
              <Subtitle>The cards in this deck so far</Subtitle>
              <Block>
                <Table headers={['White Cards']} color="white" isCollapsible>
                  {deckTable &&
                    [...deckTable]
                      .reverse()
                      .filter((card) => card.type === 'white')
                      .map(({ text, type }) => (
                        <tr key={text}>
                          <td>{text}</td>
                          <td style={{ textAlign: 'center', padding: '.5em' }}>
                            <RegularButton onClick={e => deleteCard({
                              e, setIsDeleting,
                              type,
                              text,
                              setDeckTable,
                              location,
                              setError,
                              defaultLocation,
                              reactGA,
                            })} disabled={isDeleting}>
                              <DeleteIcon />
                            </RegularButton>
                          </td>
                        </tr>
                      ))}
                </Table>
              </Block>
              <Block>
                <Table headers={['Black Cards']} color="green" isCollapsible>
                  {deckTable &&
                    [...deckTable]
                      .reverse()
                      .filter((card) => card.type === 'black')
                      .map(({ text, type, _id }) => (
                        <tr key={text}>
                          <td>{text}</td>
                          <td style={{ textAlign: 'center', padding: '.5em' }}>
                            <RegularButton onClick={e => deleteCard({
                              e, setIsDeleting,
                              type,
                              text,
                              setDeckTable,
                              location,
                              setError,
                              defaultLocation,
                              reactGA,
                            })} disabled={isDeleting}>
                              <DeleteIcon />
                            </RegularButton>
                          </td>
                        </tr>
                      ))}
                </Table>
              </Block>
            </>
          ) : deckExists === 'no result' ? (
            <>
              <p>Deck not found. Would you like to create one?</p>
              <Link to="/create-deck">Create Deck</Link>
            </>
          ) : error &&
            (error.includes('permissions') || error.includes('exist')) ? (
                  <ErrorText>{error}</ErrorText>
                ) : (
                  <p>Loading...</p>
                )}
        </>
      ) : (
          <Wrapper>
            <Label htmlFor="searchPublicDecks">Search Public Decks</Label>
            <Input
              type="text"
              onKeyUp={(e) =>
                handleKeyUp({
                  e,
                  initialDecks,
                  setFilteredDecks,
                  setPublicDecksInputVal,
                })
              }
            />
            {filteredDecks && filteredDecks.length > 0 && (
              <ResultsList>
                {filteredDecks.map(({ name }) => (
                  <li>
                    <StyledLink to={`/edit-deck/${name}`}>
                      {name.replace(/-/g, ' ')}
                    </StyledLink>
                  </li>
                ))}
                {publicDecksInputVal &&
                  filteredDecks &&
                  !filteredDecks.length && <li>No results found.</li>}
              </ResultsList>
            )}
          </Wrapper>
        )}
      <ToastContainer
        limit={1}
        autoClose={false}
        hideProgressBar
        closeOnClick
        transition={Slide}
        pauseOnFocusLoss={false}
      />
    </Page>
  );
};

const Block = styled.div`
  display: flex;
  justify-content: center;
  width: 100%;
  margin-top: 2em;
`;
const Page = styled.div`
  min-height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
`;
const Form = styled.form`
  width: 100%;
  max-width: 270px;
`;
const GreenText = styled.span`
  color: #2cce9f;
`;
const MainHeading = styled.h1`
  color: #fff;
  margin: 0;
  font-weight: normal;
  font-size: 2em;
`;
const NameOfDeck = styled.em`
  background: linear-gradient(
    90deg,
    rgb(64, 224, 208),
    rgb(255, 140, 0),
    rgb(255, 0, 128)
  );
  border-radius: 8px;
  padding: 0 0.25em 0;
  color: #000;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  display: inline-block;
  vertical-align: bottom;
  text-transform: capitalize;
`;
const Input = styled.input`
  appearance: none;
  font-size: 1em;
  border: 0;
  margin: 0;
  padding: 0.5em 0 0.3em;
  background: transparent;
  border-bottom: 1px solid #fff;
  transition: border-color 0.25s;
  border-radius: 0;
  color: #fff;

  &:hover,
  &:focus {
    outline: 0;
    border-color: #2cce9f;
  }
`;
const Label = styled.label`
  text-align: left;
  text-transform: uppercase;
  font-size: 0.813em;
  display: block;
  font-weight: bold;
`;
const Wrapper = styled.div`
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 270px;
  justify-content: center;
  margin: 2em auto;
`;
const ResultsList = styled.ul`
  list-style: none;
  padding: 1em 0;
  position: absolute;
  top: calc(100% - 1px);
  width: 100%;
  border: 1px solid #2cce9f;
  margin: 0;
  border-radius: 0 0 8px 8px;
  max-height: 139px;
  overflow: auto;
`;
const StyledLink = styled(Link)`
  display: block;
  color: #2cce9f;
  padding: 0.5em;
  transition: color 0.25s;
  text-transform: capitalize;

  &:hover,
  &:focus {
    color: #fff;
    text-decoration: none;
  }
`;
const Subtitle = styled.h2`
  font-weight: normal;
  margin: 1em 0 0;
`;
const RegularButton = styled.button`
  appearance: none;
  transition: color 0.25s;
  background: transparent;
  color: #fff;
  padding: 1px .5em;

  @media (hover) {
    &:hover {
      color: red;
    }
  }
  &:focus {
    color: red;
    outline: 0;
  }
`;

export default EditADeck;