import React, { useState, useEffect } from 'react'

import LoadingIndicator from '../components/LoadingIndicator'
import Sleep from '../components/sleep'
import NewsEntry from '../components/newsEntry'
import Composer from '../components/composer'
import Header from '../components/header'
import Modal from '../components/modal'

import styles from './forum.module.css'
import constants from '../constants'

const forumPostPerPage = 5

function fetchEntry(postKey, forumName) {
  return new Promise((resolve) => {
    fetch(
      `${constants.apiUrl}forumEntry?forumName=${forumName}&postKey=${postKey}`,
      {
        credentials: 'include',
      }
    )
      .then((resp) => {
        return resp.json()
      })
      .then((res) => {
        resolve(res)
      })
  })
}

function fetchForum(forumName, from) {
  return new Promise((resolve) => {
    fetch(
      `${constants.apiUrl}forumEntries?forumName=${forumName}&getContent=true${
        from ? `&from=${from}` : ''
      }&count=${forumPostPerPage}`,
      {
        credentials: 'include',
      }
    )
      .then((resp) => {
        return resp.json()
      })
      .then((res) => {
        resolve(res)
      })
  })
}

function addPost(title, content, forumName) {
  return new Promise((resolve) => {
    fetch(constants.apiUrl + 'addPost', {
      method: 'POST',
      credentials: 'include',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        forumName: forumName,
        title: title,
        content: content,
      }),
    })
      .then((res) => {
        return res.json()
      })
      .then((res) => {
        resolve(res)
      })
  })
}

function updateForumPost(forum, postKey, postData) {
  return Object.keys(forum).reduce((acc, key) => {
    const entry = forum[key]
    if (key === postKey) {
      acc = {
        ...acc,
        [key]: postData,
      }
    } else {
      acc = {
        ...acc,
        [key]: entry,
      }
    }
    return acc
  }, {})
}

const NewsEntryContainer = ({
  postKey,
  setNews,
  news,
  userId,
  newsEntryData,
  onTitleClick,
  forumName,
}) => {
  const [error, setError] = useState(false)

  useEffect(() => {
    if (!newsEntryData && !error) {
      fetchEntry(postKey, forumName)
        .then((res) => {
          const { success, entry, msg } = res
          if (success) {
            setNews({ [postKey]: entry, ...news })
          } else {
            alert(msg)
            setError(true)
          }
        })
        .catch((e) => {
          console.error(e)
          setError(true)
        })
    }
  }, [])

  if (!newsEntryData) {
    return <LoadingIndicator />
  }

  if (error) {
    return <div>Lil fuckup</div>
  }

  return (
    <NewsEntry
      onTitleClick={onTitleClick}
      uid={userId}
      key={postKey}
      newsKey={postKey}
      newsItem={newsEntryData}
      onPostDelete={() => {
        fetch(constants.apiUrl + 'rmPost', {
          method: 'POST',
          credentials: 'include',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            forumName: forumName,
            postKey: postKey,
          }),
        })
          .then((res) => {
            return res.json()
          })
          .then((res) => {
            const { success, msg } = res
            if (success) {
              setNews(
                Object.keys(news).reduce((acc, key) => {
                  const entry = news[key]
                  if (key !== postKey) {
                    acc = {
                      ...acc,
                      [key]: entry,
                    }
                  }
                  return acc
                }, {})
              )
            } else {
              alert(msg)
            }
          })
      }}
      onNewsReact={({ reaction, isDelete }) => {
        fetch(constants.apiUrl + 'react', {
          method: 'POST',
          credentials: 'include',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            reaction: reaction,
            postKey: postKey,
            isDelete: isDelete,
            forumName: forumName,
          }),
        })
          .then((res) => {
            return res.json()
          })
          .then((res) => {
            setNews(updateForumPost(news, postKey, res.postData))
          })
      }}
      onCommentReact={({ path, reaction, isDelete }) => {
        fetch(constants.apiUrl + 'react', {
          method: 'POST',
          credentials: 'include',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            type: 'reaction',
            postKey: postKey,
            path: path,
            reaction: reaction,
            isDelete: isDelete,
            forumName: forumName,
          }),
        })
          .then((res) => {
            return res.json()
          })
          .then((res) => {
            const { success, postData, msg } = res
            if (success) {
              setNews(updateForumPost(news, postKey, postData))
            } else {
              alert(msg)
            }
          })
      }}
      onDelete={(path) => {
        fetch(constants.apiUrl + 'comment', {
          method: 'POST',
          credentials: 'include',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            type: 'delete',
            path: path,
            postKey: postKey,
            forumName: forumName,
          }),
        })
          .then((res) => {
            return res.json()
          })
          .then((res) => {
            const { success, postData, msg } = res
            if (success) {
              setNews(updateForumPost(news, postKey, postData))
            } else {
              alert(msg)
            }
          })
      }}
      onComment={(path, content) => {
        fetch(constants.apiUrl + 'comment', {
          method: 'POST',
          credentials: 'include',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            type: 'add',
            path: path,
            content: content,
            postKey: postKey,
            forumName: forumName,
          }),
        })
          .then((res) => {
            return res.json()
          })
          .then((res) => {
            const { success, postData, msg } = res
            if (success) {
              setNews(updateForumPost(news, postKey, postData))
            } else {
              alert(msg)
            }
          })
      }}
    />
  )
}

export default function Forum({
  router,
  globalData,
  globalState,
  setGlobalState,
  forumName,
  allowPost,
}) {
  const userId = globalData.userId
  const [news, setNews] = useState(null)
  const [nextEntryKey, setNextEntryKey] = useState()
  const [fetchingForum, setFetchingForum] = useState(false)
  const [postInModalKey, setPostInModalKey] = useState()
  const [isUploading, setIsUploading] = useState(false)

  useEffect(() => {
    if (globalState[forumName]) {
      const { entries, nextKey } = globalState[forumName]
      setNextEntryKey(nextKey)
      setNews(entries)
    } else {
      setFetchingForum(true)
      fetchForum(forumName).then((res) => {
        setFetchingForum(false)
        const { entries, nextKey } = res
        setNextEntryKey(nextKey)
        setNews(entries)
        setGlobalState({ [forumName]: res })
      })
    }
  }, [])

  useEffect(() => {
    const postKey = router.query.postKey
      ? decodeURIComponent(router.query.postKey)
      : ''

    if (postKey) {
      setPostInModalKey(postKey)
    }
  }, [router.query.postKey])

  const renderNews = () => {
    if (news) {
      const newsItems = Object.keys(news).map((postKey) => {
        const newsEntryData = news[postKey]
        return (
          <NewsEntryContainer
            forumName={forumName}
            onTitleClick={() => {
              setPostInModalKey(postKey)
              router.replace(
                `${router.pathname}?postKey=${encodeURIComponent(postKey)}`,
                undefined,
                { shallow: true }
              )
            }}
            key={postKey}
            postKey={postKey}
            setNews={setNews}
            news={news}
            userId={userId}
            newsEntryData={newsEntryData}
          />
        )
      })

      return (
        <div>
          {allowPost && (
            <Composer
              onSubmit={(title, content) => {
                setIsUploading(true)

                addPost(title, content, forumName).then((res) => {
                  const { success, newPostKey, newEntry, msg } = res
                  if (success) {
                    setNews({ [newPostKey]: newEntry, ...news })
                  } else {
                    alert(msg)
                  }
                  setIsUploading(false)
                })
              }}
            />
          )}
          {isUploading && (
            <div
              style={{
                display: 'flex',
                alignItems: 'center',
                flexDirection: 'column',
              }}
            >
              {'Feltöltés ...'}
              <LoadingIndicator />
            </div>
          )}
          <div>{newsItems}</div>
          {nextEntryKey ? (
            <div
              className={styles.loadMoreButton}
              onClick={() => {
                if (fetchingForum) {
                  return
                }

                setFetchingForum(true)
                fetchForum(forumName, nextEntryKey).then((res) => {
                  setFetchingForum(false)

                  const { entries, nextKey } = res
                  setNextEntryKey(nextKey)
                  setNews({ ...news, ...entries })
                  setGlobalState({
                    news: {
                      entries: { ...news, ...entries },
                      nextKey: nextKey,
                    },
                  })
                })
              }}
            >
              {fetchingForum ? (
                <LoadingIndicator />
              ) : (
                'Több bejegyzés betöltése'
              )}
            </div>
          ) : (
            <div
              style={{
                padding: 16,
                display: 'flex',
                justifyContent: 'center',
                fontStyle: 'italic',
              }}
            >
              {newsItems.length === 0 ? 'Üres fórum' : 'The end'}
            </div>
          )}
        </div>
      )
    } else {
      return <LoadingIndicator />
    }
  }

  return (
    <div>
      <Header />
      <Sleep />
      {renderNews()}
      {postInModalKey && (
        <Modal
          closeClick={() => {
            setPostInModalKey(undefined)
            router.replace(router.pathname, undefined, { shallow: true })
          }}
        >
          {news ? (
            <NewsEntryContainer
              postKey={postInModalKey}
              setNews={setNews}
              news={news}
              userId={userId}
              newsEntryData={news[postInModalKey]}
            />
          ) : (
            <LoadingIndicator />
          )}
        </Modal>
      )}
    </div>
  )
}
