import { Button, InputGroup, Label } from '@blueprintjs/core'
import { css } from '@emotion/css'
import { useHost } from '@inject/graphql/connection/host'
import { loginUrl } from '@inject/shared/config'
import { notifyNoncommmit } from '@inject/shared/notification/var/notifications'
import authenticatedFetch from '@inject/shared/utils/authenticatedFetch'
import type { FormEvent } from 'react'
import { useCallback, useRef, useState } from 'react'
import { sessionid } from './sessionid'

const fields = css`
  display: flex;
  flex-direction: column;
  gap: 1rem;
`

const label = css`
  margin-bottom: 0 !important;
`

const loginForm = css`
  display: flex;
  flex-direction: column;
  gap: 2rem;
  margin: 0 auto;
  max-width: 30rem;
  padding: 1rem;
  width: 100%;
`

const Login = () => {
  const host = useHost()

  const username = useRef<HTMLInputElement>(null)
  const password = useRef<HTMLInputElement>(null)
  const [showPassword, setShowPassword] = useState(false)

  const [loading, setLoading] = useState(false)
  const login = useCallback(async () => {
    if (!host) {
      return
    }
    if (
      !username.current ||
      !password.current ||
      !username.current.value ||
      !password.current.value
    ) {
      notifyNoncommmit('Fill in username or password', {
        intent: 'danger',
      })
      return
    }
    try {
      setLoading(true)
      const req = await authenticatedFetch(loginUrl(host), {
        body: JSON.stringify({
          username: username.current.value,
          password: password.current.value,
        }),
        method: 'POST',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
      })
      const res: { sessionid: string } = await req.json()
      localStorage.clear()
      sessionStorage.clear()
      indexedDB.deleteDatabase('graphcache-v3')
      if (req.status === 403) {
        throw res as unknown as { status: string; detail: string }
      }
      sessionid(res.sessionid)
    } catch (err) {
      const { detail } = err as { status: string; detail: string }
      notifyNoncommmit(detail, {
        intent: 'danger',
      })
    } finally {
      setLoading(false)
    }
  }, [host, password, username])

  const handleSubmit = useCallback(
    (e: FormEvent<HTMLFormElement>) => {
      e.preventDefault()
      login()
    },
    [login]
  )

  return (
    <div>
      <form onSubmit={handleSubmit} className={loginForm}>
        <div className={fields}>
          <Label className={label}>
            Email
            <InputGroup
              id='username'
              inputRef={username}
              placeholder='email@inject.ex'
              required
              autoComplete='email'
            />
          </Label>
          <Label className={label}>
            Password
            <InputGroup
              id='password'
              inputRef={password}
              type={showPassword ? 'text' : 'password'}
              required
              autoComplete='current-password'
              placeholder='password'
              rightElement={
                <Button
                  minimal
                  icon={showPassword ? 'eye-off' : 'eye-open'}
                  onClick={() => setShowPassword(prev => !prev)}
                />
              }
            />
          </Label>
        </div>

        <Button icon='log-in' type='submit' loading={loading} intent='primary'>
          Login
        </Button>
      </form>
    </div>
  )
}

export default Login
