import React, { useState, useEffect, useCallback } from 'react'
import Link from 'next/link'

import LoadingIndicator from '../components/LoadingIndicator'
import Modal from '../components/modal'
import SearchBar from '../components/searchBar'
import UpDownVote from '../components/upDownVote'
import Header from '../components/header'

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

function vote(to, item) {
  return new Promise((resolve, reject) => {
    fetch(`${constants.apiUrl}voteFile`, {
      method: 'POST',
      credentials: 'include',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        path: item.path,
        to: to,
      }),
    })
      .then((resp) => {
        return resp.json()
      })
      .then((res) => {
        if (res.success) {
          resolve(res)
        } else {
          reject(res)
        }
      })
  })
}

function listUserDir(subdir) {
  return new Promise((resolve, reject) => {
    fetch(
      `${constants.apiUrl}listUserDir${subdir ? `?subdir=${subdir}` : ''}`,
      {
        credentials: 'include',
      }
    )
      .then((resp) => {
        return resp.json()
      })
      .then((res) => {
        if (res.success) {
          resolve(res)
        } else {
          reject(res)
        }
      })
  })
}

function FileUploader({ onChange, uploading }) {
  return (
    <div>
      <div className={styles.text}>
        <b>
          Fontos a névtelenség, ezért figyelj rá milyen személyes adatokat
          tartalmaz a feltöltött dokumentum!
        </b>
        <p />
        Amit feltöltesz minden felhasználó lát. Csak ide illő tartalmat ossz
        meg.
        <p />
      </div>
      {uploading ? (
        <LoadingIndicator />
      ) : (
        <input type="file" name="file" onChange={onChange} />
      )}
    </div>
  )
}

function SubjNameInput({ onChange, uploading }) {
  return (
    <>
      <div className={styles.text}>
        Tárgyat kérlek úgy nevezd el, hogy: [tárgy neve] - [egyetem rövid
        azonosító], szóval pl: Elektronika - OE.
        <p />
        Üres mappák időnként törölve lesznek.
      </div>
      <p />
      {uploading ? (
        <LoadingIndicator />
      ) : (
        <div>
          <input
            autoFocus
            placeholder={'Új tárgy neve'}
            type="text"
            onChange={(e) => {
              onChange(e.target.value)
            }}
          />
        </div>
      )}
    </>
  )
}

function deleteFile(currDir, name) {
  return new Promise((resolve) => {
    fetch(constants.apiUrl + 'deleteUserFile', {
      method: 'POST',
      credentials: 'include',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        dir: currDir,
        fname: name,
      }),
    })
      .then((res) => {
        return res.json()
      })
      .then((res) => {
        if (res.success) {
          resolve(res)
        } else {
          alert(res.msg)
        }
      })
  })
}

function newSubj(name) {
  return new Promise((resolve) => {
    fetch(constants.apiUrl + 'newUserDir', {
      method: 'POST',
      credentials: 'include',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        name: name,
      }),
    })
      .then((res) => {
        return res.json()
      })
      .then((res) => {
        if (res.success) {
          resolve(res)
        } else {
          alert(res.msg)
        }
      })
  })
}

function uploadFile(dir, file) {
  return new Promise((resolve) => {
    const formData = new FormData() // eslint-disable-line
    formData.append('file', file)
    formData.append('dir', dir)

    fetch(constants.apiUrl + 'uploadUserFile', {
      method: 'POST',
      credentials: 'include',
      headers: {
        Accept: 'application/json',
      },
      body: formData,
    })
      .then((res) => {
        return res.json()
      })
      .then((res) => {
        resolve(res)
      })
  })
}

export default function UserFiles({
  router,
  globalData,
  globalState,
  setGlobalState,
}) {
  const userId = globalData.userId
  const [dirs, setDirs] = useState()
  const [sortBy, setSortBy] = useState('name')
  const [sortDirection, setSortDirection] = useState(true)
  const [addingNew, setAddingNew] = useState()
  const [newSubjName, setNewSubjName] = useState()
  const [file, setFile] = useState()
  const [searchTerm, setSearchTerm] = useState()
  const [uploading, setUploading] = useState(false)
  const [votingDisabled, setVotingDisabled] = useState(false)

  const currDir = router.query.dir ? decodeURIComponent(router.query.dir) : ''

  const goBack = useCallback(() => {
    router.back()
    // FIXME: consistend going back with browser back button
    //
    // back button works like broser back button, unless it would result in site leave
    // history: nothing > opened site/usrFiles?dir=...
    // history: site > site/userFiles > site/usrFiles?dir=...
    router.push(`${router.pathname}`, undefined, {
      shallow: true,
    })
  }, [router])

  const deleteDirectory = useCallback(
    (dirName) => {
      fetch(constants.apiUrl + 'deleteDir', {
        method: 'POST',
        credentials: 'include',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          name: dirName,
        }),
      })
        .then((res) => {
          return res.json()
        })
        .then((res) => {
          console.info(res)
          if (res.succes) {
            getRootDir(true)
            alert(`a(z) '${dirName}' mappa törölve!`)
          } else {
            alert('Hiba törlés közben!')
          }
        })
        .catch((e) => {
          alert('Hálózati hiba!')
          console.error(e)
        })
    },
    [router]
  )

  useEffect(() => {
    router.replace(`${router.asPath.replace('.html', '')}`, undefined, {
      shallow: true,
    })
  }, [])

  useEffect(() => {
    const dir = router.query.dir ? decodeURIComponent(router.query.dir) : ''
    setDirs(null)
    setSearchTerm()

    if (router.query.dir) {
      getDir(dir)
    } else {
      getRootDir()
    }
  }, [router.query.dir])

  const getDir = (dir, nocache) => {
    if (!nocache && globalState.userFiles && globalState.userFiles[dir]) {
      setDirs(globalState.userFiles[dir])
    } else {
      listUserDir(dir)
        .then((res) => {
          setDirs(res.files)
          setGlobalState({
            userFiles: {
              ...globalState.userFiles,
              [dir]: res.files,
            },
          })
        })
        .catch((res) => {
          alert(res.msg)
        })
    }
  }

  const getRootDir = (nocache) => {
    if (!nocache && globalState.userFilesRoot) {
      setDirs(globalState.userFilesRoot)
    } else {
      listUserDir()
        .then((res) => {
          setGlobalState({
            userFilesRoot: res.dirs,
          })
          setDirs(res.dirs)
        })
        .catch((res) => {
          alert(res.msg)
        })
    }
  }

  const dirSorter = (a, b) => {
    if (a[sortBy] < b[sortBy]) {
      return sortDirection ? -1 : 1
    } else if (a[sortBy] > b[sortBy]) {
      return sortDirection ? 1 : -1
    } else {
      return 0
    }
  }

  const handleVote = (type, dir) => {
    setVotingDisabled(true)
    vote(type, dir)
      .then((res) => {
        setDirs(res.files)
        setVotingDisabled(false)
      })
      .catch((res) => {
        alert(res.msg)
        setVotingDisabled(false)
      })
  }

  const renderNewButton = () => (
    <div className={`buttonContainer ${styles.newButton}`}>
      <div
        onClick={() => {
          setAddingNew(currDir ? 'file' : 'dir')
        }}
      >
        {currDir ? 'Új fájl feltöltése...' : '➕ Új tárgy hozzáadása...'}
      </div>
    </div>
  )

  const renderDirList = (dirs) => {
    return (
      <div>
        {currDir && (
          <div className={styles.title}>
            {currDir && <div className={styles.currDir}>{currDir}</div>}
          </div>
        )}
        <div style={{ display: 'flex' }}>
          <div style={{ flexGrow: 1 }}>
            <SearchBar
              searchTerm={searchTerm}
              onChange={(e) => {
                setSearchTerm(e)
              }}
            />
          </div>
          {renderNewButton()}
        </div>
        <div className={`${styles.tableContainer} ${styles.header}`}>
          <div
            onClick={(e) => {
              const name = e.target.getAttribute('name')
              if (name) {
                if (sortBy === name) {
                  setSortDirection(!sortDirection)
                } else {
                  setSortDirection(true)
                }
                setSortBy(name)
              }
            }}
          >
            <div name="name">Fájl név</div>
            <div name="date">Feltöltés dátuma</div>
            <div name="size">Méret</div>
            <div name="upCount">Hasznos</div>
            <div name="views">Letöltések</div>
            <div name="user">Feltöltő user</div>
          </div>
        </div>
        {dirs ? (
          <div className={`${styles.tableContainer} ${styles.rows}`}>
            {currDir && (
              <div
                style={{
                  height: 40,
                  justifyContent: 'center',
                  display: 'flex',
                }}
                onClick={() => {
                  goBack()
                }}
              >
                {'Vissza'}
              </div>
            )}
            {dirs.length !== 0 ? (
              <>
                {dirs.sort(dirSorter).map((dir) => {
                  const {
                    name,
                    date,
                    path,
                    size,
                    views,
                    user,
                    upvotes,
                    downvotes,
                  } = dir

                  if (
                    searchTerm &&
                    !name.toLowerCase().includes(searchTerm.toLowerCase())
                  ) {
                    return null
                  }
                  return (
                    <div
                      title={name}
                      key={name}
                      onClick={() => {
                        if (path) {
                          window.open(`${constants.apiUrl}${path}`, '_blank')
                        } else {
                          setDirs(undefined)
                          router.push(
                            `${router.pathname}?dir=${encodeURIComponent(
                              name
                            )}`,
                            undefined,
                            { shallow: true }
                          )
                        }
                      }}
                    >
                      <div>{name}</div>
                      <div title={new Date(date).toLocaleString()}>
                        {new Date(date).toLocaleDateString()}
                      </div>
                      <div>
                        {currDir
                          ? (size / 1000000).toFixed(2).toString() + ' MB'
                          : size + ' fájl'}
                      </div>
                      <div>
                        {Array.isArray(upvotes) && Array.isArray(downvotes) && (
                          <UpDownVote
                            onUp={() => {
                              handleVote('up', dir)
                            }}
                            onDown={() => {
                              handleVote('down', dir)
                            }}
                            onClear={() => {
                              handleVote('clear', dir)
                            }}
                            upvotes={upvotes}
                            downvotes={downvotes}
                            userId={userId}
                            disabled={votingDisabled}
                          />
                        )}
                      </div>
                      <div>{!isNaN(views) && `${views} db`}</div>
                      <div>
                        {user &&
                          user !== -1 &&
                          (userId === user ? (
                            <div
                              className={styles.deleteButton}
                              onClick={(e) => {
                                e.stopPropagation()
                                if (confirm(`Biztos törlöd '${name}'-t ?`)) {
                                  deleteFile(currDir, name).then(() => {
                                    getDir(currDir, true)
                                  })
                                }
                              }}
                            >
                              Törlés
                            </div>
                          ) : (
                            <Link
                              href={`/chat?user=${user}`}
                              title={`Chat #${user}-el`}
                              onClick={(e) => {
                                e.stopPropagation()
                              }}
                              className={'userId'}
                            >
                              {`#${user}`}
                            </Link>
                          ))}
                      </div>
                    </div>
                  )
                })}
              </>
            ) : (
              <div
                title={'A megnyitott mappa törlése, mivel üres'}
                onClick={() => {
                  if (
                    window.confirm(
                      `Biztosan törlöd a(z) '${currDir}' üres mappát?`
                    )
                  ) {
                    deleteDirectory(currDir)
                    goBack()
                  }
                }}
              >
                {'Mappa törlése'}
              </div>
            )}
          </div>
        ) : (
          <LoadingIndicator />
        )}
      </div>
    )
  }

  return (
    <div>
      <Header title={'ZH-k/Vizsgák, segédanyagok'} />
      <div className="pageHeader">
        <h1>ZH-k/Vizsgák, segédanyagok</h1>
      </div>
      {!currDir && (
        <div className={styles.description}>
          Itt lehet megosztani mindenféle tanulást segítő doksit (kidolgozott
          tételektől puskáig mindent).
          <br />
          Ez gyakorlatilag egy fájl böngésző, a tárgyak a mappák, és azon belül
          lehet fájlokat feltölteni.
          <br />A feltöltött fájlok ellenőrizve vannak, hogy ide valóak-e, de{' '}
          <b>
            hibás információért, vírusokért és hasonlókért semmi felelősség
            vállalás nincs.
          </b>{' '}
          Ha valami nem idevalót látsz, azt a{' '}
          <Link href="/contact">Kapcsolat</Link> oldalon jelezd kérlek. Tudatos
          károkozásért ban jár.
        </div>
      )}
      <hr />
      {renderDirList(dirs)}
      {addingNew && (
        <Modal
          closeClick={() => {
            setAddingNew(null)
          }}
        >
          <div className={styles.uploadContainer}>
            {addingNew === 'file' ? (
              <>
                <FileUploader
                  uploading={uploading}
                  onChange={(e) => {
                    setFile(e.target.files[0])
                  }}
                />
                <div
                  className="buttonContainer"
                  onClick={() => {
                    setUploading(true)
                    uploadFile(currDir, file).then(() => {
                      setUploading(false)
                      setAddingNew(null)
                      getDir(currDir, true)
                    })
                  }}
                >
                  <div>Feltöltés</div>
                </div>
              </>
            ) : (
              <>
                <SubjNameInput
                  uploading={uploading}
                  onChange={(e) => {
                    setNewSubjName(e)
                  }}
                />
                <div
                  className="buttonContainer"
                  onClick={() => {
                    setUploading(true)
                    newSubj(newSubjName).then(() => {
                      setUploading(false)
                      setAddingNew(null)
                      getRootDir(true)
                      alert(`'${newSubjName}' létrehozva!`)
                    })
                  }}
                >
                  <div>
                    {addingNew === 'file' ? 'OK' : 'Új mappa létrehozása'}
                  </div>
                </div>
              </>
            )}
          </div>
        </Modal>
      )}
    </div>
  )
}
