'use client'

import { useEffect, useState } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import { Button } from 'flowbite-react'
import { toast } from 'react-toastify'
import { useForm } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers/yup'

import { useAuth } from '@/lib/context/AuthContext'
import { paginationDefaultData } from '@/lib/data/pagination'
import * as PaginationConstant from '@/lib/constants/pagination'
import * as referralLinkServices from '@/lib/services/referral-link-services'
import { handleApiError } from '@/lib/utils/error-handler'
import { constructSearchURL } from '@/lib/utils/url'
import buttonTheme from '@/lib/themes/button'
import PaginationComponent from '@/lib/components/Pagination'
import { ReferralLinkFormValues, referralLinkSchema } from './schema'
import { ReferralLink, SearchFormProps } from './types'
import DataTable from './partials/DataTable'
import SearchForm from './partials/SearchForm'
import ModalForm from './partials/ModalForm'
import DeleteModal from './partials/DeleteModal'

export default function MainContent() {
  const router = useRouter()
  const { user } = useAuth()
  const searchParams = useSearchParams()
  const [refreshTrigger, setRefreshTrigger] = useState(0)
  const [selectedReferralLink, setSelectedReferralLink] =
    useState<ReferralLink | null>(null)
  const [referralLinks, setReferralLinks] = useState<Pagination<ReferralLink>>(
    paginationDefaultData,
  )
  const [searchForm, setSearchForm] = useState<SearchFormProps>({
    searching: false,
    params: {
      link_name: searchParams.get('link_name') || '',
      user_id: searchParams.get('user_id') || '',
      page: searchParams.get('page') ? Number(searchParams.get('page')) : 1,
      limit: searchParams.get('limit')
        ? Number(searchParams.get('limit'))
        : PaginationConstant.MIN_DATA_PER_PAGE,
    },
  })
  const [isLoadingInitial, setIsLoadingInitial] = useState(true)
  const [modal, setModal] = useState<ModalState<ReferralLink>>({
    isOpened: false,
    processing: false,
    type: 'create',
    data: null,
  })

  const form = useForm<ReferralLinkFormValues>({
    resolver: yupResolver(referralLinkSchema),
  })

  function handleOpenCreateModal() {
    form.reset({
      link_name: '',
      link_url: '',
      user_id: '',
    })

    setSelectedReferralLink(null)

    setModal({
      type: 'create',
      isOpened: true,
      processing: false,
      data: null,
    })
  }

  function handleOpenEditModal(referralLink: ReferralLink) {
    form.reset({
      link_name: referralLink.link_name,
      link_url: referralLink.link_url,
      user_id: referralLink.user_id?.toString() || '',
    })

    setSelectedReferralLink(referralLink)

    setModal({
      type: 'edit',
      isOpened: true,
      processing: false,
      data: referralLink,
    })
  }

  function handleOpenDeleteModal(referralLink: ReferralLink) {
    setSelectedReferralLink(referralLink)

    setModal({
      type: 'delete',
      isOpened: true,
      processing: false,
      data: referralLink,
    })
  }

  function handleCloseModal() {
    form.reset()

    setModal((prev) => ({
      ...prev,
      isOpened: false,
      data: null,
    }))
  }

  async function handleSubmitForm(formValues: ReferralLinkFormValues) {
    setModal((prev) => ({ ...prev, processing: true }))

    try {
      if (modal.type === 'edit' && selectedReferralLink?.id) {
        const updatedReferralLink =
          await referralLinkServices.updateReferralLink(
            selectedReferralLink.id,
            formValues,
          )

        setReferralLinks((prev) => ({
          ...prev,
          data: prev.data.map((item) =>
            item.id === updatedReferralLink.id ? updatedReferralLink : item,
          ),
        }))

        toast.success('Referral link updated successfully!')
      } else {
        const newReferralLink =
          await referralLinkServices.createReferralLink(formValues)

        const totalData = referralLinks.total + 1
        const lastPage = Math.ceil(totalData / referralLinks.per_page)
        const prevData =
          referralLinks.data.length < referralLinks.per_page
            ? referralLinks.data
            : referralLinks.data.slice(0, -1)

        setReferralLinks((prev) => ({
          ...prev,
          last_page: lastPage,
          total: prev.total + 1,
          from: prev.from ? prev.from : 1,
          to: totalData < prev.per_page ? totalData : prev.per_page,
          data: [newReferralLink, ...prevData],
        }))

        toast.success('Referral link created successfully!')
      }

      form.reset()

      setModal({
        type: 'create',
        isOpened: false,
        processing: false,
        data: null,
      })
    } catch (err) {
      handleApiError(
        err,
        'Oops! Something went wrong. Please try again later.',
        (formErrors) => {
          Object.keys(formErrors).forEach((field) => {
            form.setError(field as keyof ReferralLinkFormValues, {
              type: 'manual',
              message: formErrors[field][0],
            })
          })
        },
      )
    } finally {
      setModal((prev) => ({ ...prev, processing: false }))
    }
  }

  async function handleConfirmDelete() {
    if (!selectedReferralLink?.id) return

    setModal((prev) => ({ ...prev, processing: true }))

    try {
      await referralLinkServices.deleteReferralLink(selectedReferralLink.id)

      const updatedReferralLinks = await referralLinkServices.getReferralLinks({
        link_name: searchParams.get('link_name') || '',
        user_id: searchParams.get('user_id') || '',
      })

      if (
        updatedReferralLinks.data.length === 0 &&
        updatedReferralLinks.current_page > 1
      ) {
        const prevPage = updatedReferralLinks.current_page - 1

        setSearchForm((prev) => ({
          ...prev,
          params: {
            ...prev.params,
            page: prevPage,
            limit: referralLinks.per_page,
          },
        }))

        return router.push(
          constructSearchURL('/referral-links', {
            ...searchForm.params,
            page: prevPage,
            limit: referralLinks.per_page,
          }),
        )
      }

      setReferralLinks(updatedReferralLinks)
      setSelectedReferralLink(null)
      setModal({
        type: 'delete',
        isOpened: false,
        processing: false,
        data: null,
      })

      toast.success('Referral link deleted successfully!')
    } catch {
      toast.error(
        'Oops! Something went wrong on delete referral link. Please try again later.',
      )
    }
  }

  async function handleSearchSubmit(e?: React.FormEvent) {
    e?.preventDefault()

    setSearchForm((prev) => ({ ...prev, searching: true }))
    setReferralLinks(paginationDefaultData)

    const newUrl = constructSearchURL('/referral-links', {
      ...searchForm.params,
      page: 1,
    })

    const currentUrl = `${window.location.pathname}${window.location.search}`

    if (currentUrl === newUrl) {
      setRefreshTrigger((prev) => prev + 1)
      return
    }

    return router.push(newUrl)
  }

  async function handlePageChange(page: number) {
    setSearchForm((prev) => ({
      ...prev,
      params: {
        ...prev.params,
        page,
      },
    }))

    return router.push(
      constructSearchURL('/referral-links', {
        ...searchForm.params,
        page,
      }),
    )
  }

  function handleLimitChange(limit: number) {
    setSearchForm((prev) => ({
      ...prev,
      params: {
        ...prev.params,
        page: 1,
        limit,
      },
    }))

    return router.push(
      constructSearchURL('/referral-links', {
        ...searchForm.params,
        page: 1,
        limit,
      }),
    )
  }

  useEffect(() => {
    setIsLoadingInitial(true)

    referralLinkServices
      .getReferralLinks({
        link_name: searchParams.get('link_name') || '',
        user_id: searchParams.get('user_id') || '',
        page: Number(searchParams.get('page') ?? 1),
        limit: Number(
          searchParams.get('limit') ?? PaginationConstant.MIN_DATA_PER_PAGE,
        ),
      })
      .then(setReferralLinks)
      .catch(() => {
        toast.error('Failed to load referral links. Please try again.')
      })
      .finally(() => {
        setIsLoadingInitial(false)
        setSearchForm((prev) => ({ ...prev, searching: false }))
      })
  }, [searchParams, refreshTrigger])

  // Authorize User
  useEffect(() => {
    if (user && user.role !== 'super_admin' && user.role !== 'manager') {
      router.replace('/')
    }
  }, [user, router])

  return (
    <section className="mt-8">
      <div>
        <h1 className="text-3xl font-semibold text-black mb-2">
          Referral Links
        </h1>
        <p className="font-medium text-slate-500">
          Following are the list of referral links. You can manage them here.
        </p>

        <Button
          theme={buttonTheme.button}
          color="default"
          className="mt-4"
          onClick={handleOpenCreateModal}
        >
          Create Referral Link
        </Button>
      </div>

      <SearchForm
        searchForm={searchForm}
        handleSearch={handleSearchSubmit}
        setSearchForm={setSearchForm}
      />

      <DataTable
        referralLinks={searchForm.searching ? [] : referralLinks.data}
        isLoading={isLoadingInitial}
        onEdit={handleOpenEditModal}
        onDelete={handleOpenDeleteModal}
      />

      {!isLoadingInitial && (
        <PaginationComponent
          currentPage={referralLinks.current_page}
          lastPage={referralLinks.last_page}
          limit={
            searchParams.get('limit')
              ? Number(searchParams.get('limit'))
              : PaginationConstant.MIN_DATA_PER_PAGE
          }
          from={referralLinks.from}
          to={referralLinks.to}
          total={referralLinks.total}
          handlePageChange={handlePageChange}
          handleLimitChange={handleLimitChange}
        />
      )}

      <ModalForm
        isOpen={modal.isOpened && modal.type !== 'delete'}
        type={modal.type as 'create' | 'edit'}
        isProcessing={modal.processing ?? false}
        form={form}
        referralLink={modal.data as ReferralLink}
        onClose={handleCloseModal}
        onSubmit={handleSubmitForm}
      />

      <DeleteModal
        isOpen={modal.isOpened && modal.type === 'delete'}
        referralLink={selectedReferralLink}
        isDeleting={modal.processing ?? false}
        onClose={() => setModal((prev) => ({ ...prev, isOpened: false }))}
        onConfirm={handleConfirmDelete}
      />
    </section>
  )
}
