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

import Header from '../components/header'
import LoadingIndicator from '../components/LoadingIndicator'
import QuestionSearchResult from '../components/QuestionSearchResult'
import Subject from '../components/Subject'
import SubjectSelector from '../components/SubjectSelector'
import ExternalLinkIcon from '../components/externalLinkIcon'
import SearchBar from '../components/searchBar'

import styles from './allQuestions.module.css'

import constants from '../constants.json'

const countReducer = (acc, subj) => {
  return acc + subj.Questions.length
}

function mergeData(data) {
  return data.reduce((acc, db) => {
    return [
      ...acc,
      ...db.data.map((subj) => {
        return {
          ...subj,
          Name: `${subj.Name} [ DB: ${db.dbName} ]`,
        }
      }),
    ]
  }, [])
}

function fetchData(db) {
  return new Promise((resolve) => {
    fetch(`${constants.apiUrl}${db.path}`, {
      credentials: 'include',
    })
      .then((resp) => {
        return resp.json()
      })
      .then((resp) => {
        resolve({
          dbName: db.name,
          data: resp,
        })
      })
  })
}

function fetchAllData(dbs) {
  const promises = dbs.map((db) => {
    return fetchData(db)
  })

  return Promise.all(promises)
}

function fetchDbs() {
  return new Promise((resolve) => {
    fetch(`${constants.apiUrl}getDbs`, {
      credentials: 'include',
    })
      .then((resp) => {
        return resp.json()
      })
      .then((data) => {
        resolve(data)
      })
  })
}

export default function AllQuestions({ router, globalState, setGlobalState }) {
  const [subjectsShowing, setSubjectsShowing] = useState(false)
  const [searchTerm, setSearchTerm] = useState('')
  const [activeSubjName, setActiveSubjName] = useState('')
  const [dbs, setDbs] = useState(null)
  const [selectedDb, setSelectedDb] = useState(-1)
  const [data, setData] = useState(null)
  const [fetchingData, setFetchingData] = useState(false)

  const subjectCount = data ? data.length : 0
  const questionCount = data ? data.reduce(countReducer, 0) : 0

  useEffect(() => {
    router.replace(`${router.asPath.replace('.html', '')}`, undefined, {
      shallow: true,
    })
    if (globalState.qdbs) {
      setDbs(globalState.qdbs)
    } else {
      fetchDbs().then((res) => {
        setDbs(res)
        setGlobalState({
          qdbs: res,
        })
      })
    }
  }, [])

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

    if (db) {
      setSelectedDb(db)
    }
  }, [router.query.db])

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

    if (querySearch) {
      setSearchTerm(querySearch)
    }
  }, [router.query.question])

  useEffect(() => {
    if (dbs && selectedDb && (selectedDb === 'all' || dbs[selectedDb])) {
      if (selectedDb === 'all') {
        const hasAll =
          globalState.dbs &&
          dbs.every((db) => {
            return (
              Object.keys(globalState.dbs).findIndex((key) => {
                return db.name === key
              }) !== -1
            )
          })

        if (hasAll) {
          const asd = Object.keys(globalState.dbs).map((key) => {
            return {
              dbName: key,
              data: globalState.dbs[key],
            }
          })
          setData(mergeData(asd))
          setFetchingData(false)
        } else {
          fetchAllData(dbs).then((res) => {
            setData(mergeData(res))
            setFetchingData(false)

            let cacheRes = {}
            res.forEach((db) => {
              cacheRes = {
                ...cacheRes,
                [db.dbName]: db.data,
              }
            })
            setGlobalState({
              dbs: cacheRes,
            })
          })
        }
      } else {
        const selected = dbs[selectedDb]
        if (globalState.dbs && globalState.dbs[selected.name]) {
          setData(globalState.dbs[selected.name])
          setFetchingData(false)
        } else {
          fetchData(dbs[selectedDb]).then((res) => {
            setData(res.data)
            setFetchingData(false)

            setGlobalState({
              dbs: {
                ...globalState.dbs,
                [res.dbName]: res.data,
              },
            })
          })
        }
      }
    }
  }, [selectedDb, dbs])

  const renderDbSelector = () => {
    if (dbs) {
      return (
        <>
          <div className={'pageHeader'}>
            <h1>Kérdések és tárgyak</h1>
          </div>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <div className={'description'}>
              Ezen az oldalon tudsz manuálisan keresni a kérdések és a tárgyak
              között, vagy ellenőrizni, hogy egy adott tárgy szerepel-e a
              kérdés- és tárgyadatbázisban. Ezen kívül a kérdéseket le is
              töltheted offline használatra. (txt formátumban)
            </div>
            <div className={'buttonContainer'}>
              <div
                onClick={() => {
                  window.open(`${constants.siteUrl}dataeditor`, '_blank')
                }}
              >
                Kérdés szerkesztő
                <ExternalLinkIcon size={15} />
              </div>
            </div>
          </div>
          <div className={'selectContainer'}>
            <select
              value={selectedDb}
              onChange={(event) => {
                const key = event.target.value
                setData(null)
                setSelectedDb(key)
                if (parseInt(key) === -1) {
                  router.replace(
                    `${router.pathname}?question=${encodeURIComponent(
                      searchTerm
                    )}`,
                    undefined,
                    { shallow: true }
                  )
                  return
                }
                setFetchingData(true)

                router.replace(
                  `${router.pathname}?question=${encodeURIComponent(
                    searchTerm
                  )}&db=${key}`,
                  undefined,
                  { shallow: true }
                )
              }}
            >
              <option value={-1}>{' Válassz egy adatbázist!'}</option>
              {dbs.map((db, i) => {
                return (
                  <option value={i} key={db.path}>
                    {db.name}
                  </option>
                )
              })}
              <option value={'all'} key={'all'}>
                {'Összes kérdés'}
              </option>
            </select>
          </div>
        </>
      )
    } else {
      return null
    }
  }

  const renderSubjectBrowser = () => {
    let currSubj = data
      ? data.find((subj) => {
          return subj.Name === activeSubjName
        })
      : {}

    return (
      <div>
        {data ? (
          <>
            <SearchBar
              searchTerm={searchTerm}
              onChange={(e) => {
                setSearchTerm(e)
              }}
            />
            <hr />
            <SubjectSelector
              data={data}
              activeSubjName={activeSubjName}
              searchTerm={searchTerm}
              onSubjSelect={(subjName) => {
                setActiveSubjName(subjName)
              }}
            />

            <div>
              <hr />
              <Subject subj={currSubj} />
            </div>
          </>
        ) : null}
      </div>
    )
  }

  const renderQuestionBrowser = () => {
    return (
      <div>
        {data ? (
          <>
            <SearchBar
              searchTerm={searchTerm}
              onChange={(e) => {
                setSearchTerm(e)
              }}
            />
            <div>
              <QuestionSearchResult data={data} searchTerm={searchTerm} />
            </div>
          </>
        ) : null}
      </div>
    )
  }

  return (
    <div>
      <Header title={'Kérdések és tárgyak'} />
      {dbs ? <>{renderDbSelector()}</> : <LoadingIndicator />}
      {dbs && data ? (
        <>
          <div className={styles.info}>
            {`Összesen ${questionCount.toLocaleString()} kérdés, ${subjectCount} tárgyból`}
          </div>
          <div className={'buttonContainer'}>
            <div
              className={!subjectsShowing ? 'activeButton' : ''}
              onClick={() => setSubjectsShowing(false)}
            >
              Kérdések
            </div>
            <div
              className={subjectsShowing ? 'activeButton' : ''}
              onClick={() => setSubjectsShowing(true)}
            >
              Tárgyak
            </div>
            <a
              onClick={() => {
                if (selectedDb === 'all') {
                  window.open(`${constants.apiUrl}allqr.txt`, '_blank')
                } else {
                  window.open(
                    `${constants.apiUrl}allqr.txt?db=${dbs[selectedDb].name}`,
                    '_blank'
                  )
                }
              }}
            >
              {'Kérdések letöltése'}
              <ExternalLinkIcon size={15} />
            </a>
          </div>
          {fetchingData ? (
            <LoadingIndicator />
          ) : (
            <div>
              {subjectsShowing
                ? renderSubjectBrowser()
                : renderQuestionBrowser()}
            </div>
          )}
        </>
      ) : fetchingData ? (
        <div>
          Kérdések betöltése, nagy adatbázisoknál ez sokáig tarthat ...
          <LoadingIndicator />
        </div>
      ) : null}
    </div>
  )
}
