import { h } from 'preact'
import { useCallback, useEffect, useState } from 'preact/hooks'
import { route } from 'preact-router'
import rek, { type FetchError } from 'rek'
import { pick } from 'lowline'

import { useNotifications } from '../contexts/notifications.tsx'
import useItemsReducer from '../hooks/use_items_reducer.ts'
import useRequestState from '../../shared/hooks/use_request_state.ts'
import Button from './button.tsx'
import ErrorDetails from './error_details.tsx'
import ErrorsSearchForm from './errors_search_form.tsx'
import ErrorsTable from './errors_table.tsx'
import Modal from './modal.tsx'
import PageHeader from './page_header.tsx'
import Pagination from './pagination.tsx'
import Section from './section.tsx'

import s from './errors_page.module.scss'

const defaultSort = '-id'

export default function ErrorsPage() {
  const { notify } = useNotifications()
  const [{ pending }, request] = useRequestState()
  const [pagination, setPagination] = useState({})
  const [errors, items] = useItemsReducer()
  const [selected, setSelected] = useState(null)

  useEffect(() => {
    fetch()
  }, [location.search])

  const fetch = useCallback(async () => {
    try {
      const { items: errors, ...pagination } = await rek(`/api/errors${location.search}`)

      items.reset(errors)
      setPagination(pagination)
    } catch (err) {
      notify.error((err as FetchError).body?.message || (err as FetchError).message)
    }
  }, [])

  const onSearchSubmit = useCallback(
    (query: ANY) => {
      const currentParams = new URLSearchParams(location.search)

      if (currentParams.has('sort')) query = { ...query, sort: currentParams.get('sort') }

      route(location.pathname + (Object.keys(query).length ? '?' + new URLSearchParams(query) : ''))
    },
    [location.search],
  )

  const onSortBy = useCallback((column: string) => {
    const searchParams = new URLSearchParams(location.search)

    searchParams.delete('offset')

    searchParams.set('sort', (searchParams.get('sort') || defaultSort) === column ? '-' + column : column)

    route(location.pathname + '?' + searchParams)
  }, [])

  const onDelete = useCallback(async (id: number) => {
    if (confirm(`Sure you want to remove error #${id}`)) {
      try {
        request.pending()

        await rek.delete(`/api/errors/${id}`)

        fetch()

        notify.success(`Successfully deleted error #${id}`)
      } catch {
        notify.error(`Failed to delete error #${id}`)
      }

      request.reset()
    }
  }, [])

  const deleteErrors = useCallback(
    async (page: ANY) => {
      if (confirm(page ? 'Delete errors on page?' : 'Delete all filtered errors?')) {
        try {
          request.pending()

          await rek.delete('/api/errors', {
            searchParams: page ? { id: errors.map((error) => error.id).join(',') } : location.search,
          })

          fetch()

          notify.success(page ? 'Errors on page deleted' : 'All filtered errors deleted')
        } catch (err) {
          notify.error(`Error deleting errors: ${(err as FetchError).body?.message || (err as FetchError).message}`)
        }

        request.reset()
      }
    },
    [errors],
  )

  return (
    <section>
      <PageHeader>Errors</PageHeader>

      <Section>
        <Section.Heading>List</Section.Heading>

        <Section.Body className={s.top}>
          <ErrorsSearchForm className={s.search} onSubmit={onSearchSubmit} />

          <div className={s.delete}>
            <Button color='red' className={s.button} onClick={() => deleteErrors(true)}>
              Delete Page
            </Button>
            <Button color='red' className={s.button} onClick={() => deleteErrors(false)}>
              Delete All
            </Button>
          </div>
        </Section.Body>

        <Section.Body noPadding>
          <Pagination {...pagination} {...pick(location, 'search', 'pathname')} />

          <ErrorsTable
            defaultSort={defaultSort}
            errors={errors}
            onDelete={onDelete}
            onSelect={setSelected}
            pending={pending}
            onSortBy={onSortBy}
          />

          <Pagination {...pagination} {...pick(location, 'search', 'pathname')} />
        </Section.Body>
      </Section>

      {selected != null && (
        <Modal onClose={() => setSelected(null)}>
          <ErrorDetails error={errors.find((error) => error.id === selected)} />
        </Modal>
      )}
    </section>
  )
}
