import { mdiChartTimelineVariant } from '@mdi/js'
import Head from 'next/head'
import { useRouter } from 'next/router'
import React, { ReactElement, useCallback, useEffect, useMemo, useState } from 'react'
import axios from 'axios'
import CardBox from '../components/CardBox'
import LayoutAuthenticated from '../layouts/Authenticated'
import SectionMain from '../components/SectionMain'
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'
import { getPageTitle } from '../config'
import ElementPreview from '../components/UiElements/ElementPreview'
import {
  getDefaultSettings,
  normalizeUiElement,
  toElementLabel,
  UI_ELEMENT_TYPES,
} from '../components/UiElements/defaults'
import { UiElementItem, UiElementRow } from '../components/UiElements/types'

const UiElementsPage = () => {
  const router = useRouter()

  const [elements, setElements] = useState<UiElementItem[]>([])
  const [isLoading, setIsLoading] = useState(false)
  const [errorMessage, setErrorMessage] = useState('')

  const fetchRows = useCallback(async () => {
    const response = await axios.get('/ui-elements?limit=1000&page=0&sort=asc&field=sort_order')
    return Array.isArray(response?.data?.rows) ? response.data.rows : []
  }, [])

  const bootstrapMissingElements = useCallback(async (rows: UiElementRow[]) => {
    const existingTypes = new Set(rows.map((row) => row.element_type))
    const missingTypes = UI_ELEMENT_TYPES.filter((type) => !existingTypes.has(type))

    const safeStartOrder = Math.max(
      1,
      ...rows
        .map((row) => Number(row.sort_order))
        .filter((value) => Number.isFinite(value))
        .map((value) => Math.trunc(value) + 1),
    )

    if (!missingTypes.length) return

    const createResults = await Promise.allSettled(
      missingTypes.map((elementType, index) =>
        axios.post('/ui-elements', {
          data: {
            element_type: elementType,
            name: toElementLabel(elementType),
            sort_order: safeStartOrder + index,
            settings_json: JSON.stringify(getDefaultSettings(elementType)),
          },
        }),
      ),
    )

    const rejected = createResults.filter((result) => result.status === 'rejected') as PromiseRejectedResult[]

    if (rejected.length) {
      const reasons = rejected
        .map((result) => {
          const err = result.reason
          return err?.response?.data?.message || err?.message || 'Unknown create error'
        })
        .join('; ')

      throw new Error(`Failed to bootstrap some UI elements: ${reasons}`)
    }
  }, [])

  const loadElements = useCallback(async () => {
    setIsLoading(true)
    setErrorMessage('')

    try {
      const initialRows = (await fetchRows()) as UiElementRow[]
      await bootstrapMissingElements(initialRows)

      const rowsAfterBootstrap = (await fetchRows()) as UiElementRow[]
      const normalized = rowsAfterBootstrap
        .map((row) => normalizeUiElement(row))
        .sort((a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name))

      setElements(normalized)
    } catch (error: any) {
      const message = error?.response?.data?.message || error?.message || 'Failed to load UI elements.'
      setErrorMessage(message)
      setElements([])
      console.error('Failed to load UI elements:', error)
    } finally {
      setIsLoading(false)
    }
  }, [bootstrapMissingElements, fetchRows])

  useEffect(() => {
    loadElements()
  }, [loadElements])

  const sortedElements = useMemo(
    () => [...elements].sort((a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name)),
    [elements],
  )

  return (
    <>
      <Head>
        <title>{getPageTitle('UI Elements')}</title>
      </Head>
      <SectionMain>
        <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title='UI Elements' main>
          {''}
        </SectionTitleLineWithButton>

        {errorMessage ? <CardBox className='mb-4 text-sm text-red-600'>{errorMessage}</CardBox> : null}

        <CardBox>
          {isLoading ? (
            <p className='text-sm text-gray-500'>Loading platform elements...</p>
          ) : !sortedElements.length ? (
            <p className='text-sm text-gray-500'>No UI elements found.</p>
          ) : (
            <div className='overflow-x-auto'>
              <table className='w-full min-w-[680px] text-sm'>
                <thead>
                  <tr className='border-b border-gray-200 text-left dark:border-dark-700'>
                    <th className='py-2 pr-3 font-semibold'>Name</th>
                    <th className='py-2 pr-3 font-semibold'>Type</th>
                    <th className='py-2 pr-3 font-semibold'>Preview</th>
                  </tr>
                </thead>
                <tbody>
                  {sortedElements.map((item) => (
                    <tr
                      key={item.id}
                      className='cursor-pointer border-b border-gray-100 hover:bg-gray-50 dark:border-dark-800 dark:hover:bg-dark-800'
                      onClick={() => router.push(`/ui-elements/${item.id}`)}
                    >
                      <td className='py-3 pr-3 font-semibold'>{item.name}</td>
                      <td className='py-3 pr-3 text-xs text-gray-500'>{toElementLabel(item.elementType)}</td>
                      <td className='py-3 pr-3'>
                        <ElementPreview item={item} />
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </CardBox>
      </SectionMain>
    </>
  )
}

UiElementsPage.getLayout = function getLayout(page: ReactElement) {
  return <LayoutAuthenticated>{page}</LayoutAuthenticated>
}

export default UiElementsPage
