'use client'

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

import * as PaginationConstant from '@/lib/constants/pagination'
import { paginationDefaultData } from '@/lib/data/pagination'
import * as affiliateLevelServices from '@/lib/services/affiliate-level-services'
import buttonTheme from '@/lib/themes/button'
import PaginationComponent from '@/lib/components/Pagination'
import { constructSearchURL } from '@/lib/utils/url'
import { useAuth } from '@/lib/context/AuthContext'
import { handleApiError } from '@/lib/utils/error-handler'
import { affiliateLevelFormSchema, AffiliateLevelFormValues } from './schema'
import { AffiliateLevel, SearchFormProps } from './types'
import SearchForm from './partials/SearchForm'
import DataTable from './partials/DataTable'
import ModalForm from './partials/ModalForm'
import DeleteModal from './partials/DeleteModal'

export default function MainContent() {
  const router = useRouter()
  const { user } = useAuth()
  const searchParams = useSearchParams()
  const [selectedLevel, setSelectedLevel] = useState<AffiliateLevel | null>(
    null,
  )
  const [affiliateLevels, setAffiliateLevels] = useState<
    Pagination<AffiliateLevel>
  >(paginationDefaultData)
  const [refreshTrigger, setRefreshTrigger] = useState(0)
  const [searchForm, setSearchForm] = useState<SearchFormProps>({
    searching: false,
    params: {
      search: searchParams.get('search') || '',
      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<AffiliateLevel>>({
    isOpened: false,
    processing: false,
    type: 'create',
    data: null,
  })

  const form = useForm<AffiliateLevelFormValues>({
    resolver: yupResolver(affiliateLevelFormSchema),
  })

  function handleOpenCreateModal() {
    form.reset({
      name: '',
      min_sales_volume: 0,
      discount_agent_rate: 0,
      min_withdrawal_amount: 0,
      max_withdrawal_amount: 0,
      withdrawal_daily_limit: 0,
      withdrawal_fee: 0,
    })
    setSelectedLevel(null)
    setModal({ type: 'create', isOpened: true, processing: false, data: null })
  }

  function handleOpenEditModal(level: AffiliateLevel) {
    form.reset({
      name: level.name,
      min_sales_volume: level.min_sales_volume,
      discount_agent_rate: parseFloat(String(level.discount_agent_rate)),
      min_withdrawal_amount: parseFloat(String(level.min_withdrawal_amount)),
      max_withdrawal_amount: parseFloat(String(level.max_withdrawal_amount)),
      withdrawal_daily_limit: level.withdrawal_daily_limit,
      withdrawal_fee: parseFloat(String(level.withdrawal_fee)),
    })
    setSelectedLevel(level)
    setModal({ type: 'edit', isOpened: true, processing: false, data: level })
  }

  function handleOpenDeleteModal(level: AffiliateLevel) {
    setSelectedLevel(level)
    setModal({
      type: 'delete',
      isOpened: true,
      processing: false,
      data: level,
    })
  }

  function handleCloseModal() {
    form.reset()
    setModal((prev) => ({ ...prev, isOpened: false }))
  }

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

    try {
      if (modal.type === 'edit' && selectedLevel?.id) {
        const updatedLevel = await affiliateLevelServices.updateAffiliateLevel(
          selectedLevel.id,
          formValues,
        )

        setAffiliateLevels((prev) => ({
          ...prev,
          data: prev.data.map((item) =>
            item.id === updatedLevel.id ? updatedLevel : item,
          ),
        }))

        toast.success('Affiliate level updated successfully!')
      } else {
        const newLevel =
          await affiliateLevelServices.createAffiliateLevel(formValues)

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

        setAffiliateLevels((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: [newLevel, ...prevData],
        }))

        toast.success('Affiliate level 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 AffiliateLevelFormValues, {
              type: 'manual',
              message: formErrors[field][0],
            })
          })
        },
      )
    } finally {
      setModal((prev) => ({ ...prev, processing: false }))
    }
  }

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

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

    try {
      await affiliateLevelServices.deleteAffiliateLevel(selectedLevel.id)

      const updatedLevels = (await affiliateLevelServices.getAffiliateLevels({
        search: searchParams.get('search') || '',
        page: Number(searchParams.get('page') ?? 1),
        limit: Number(
          searchParams.get('limit') ?? PaginationConstant.MIN_DATA_PER_PAGE,
        ),
      })) as Pagination<AffiliateLevel>

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

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

        return router.push(
          constructSearchURL('/affiliate-levels', {
            ...searchForm.params,
            page: prevPage,
            limit: affiliateLevels.per_page,
          }),
        )
      }

      setAffiliateLevels(updatedLevels as Pagination<AffiliateLevel>)
      setSelectedLevel(null)
      setModal({
        type: 'delete',
        isOpened: false,
        processing: false,
        data: null,
      })

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

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

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

    const newUrl = constructSearchURL('/affiliate-levels', {
      ...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) {
    if (isNaN(page)) {
      setSearchForm((prev) => ({
        ...prev,
        params: {
          ...prev.params,
          page: 1,
        },
      }))

      return router.push(
        constructSearchURL('/affiliate-levels', {
          ...searchForm.params,
          page: 1,
        }),
      )
    }

    setSearchForm((prev) => ({
      ...prev,
      params: {
        ...prev.params,
        page,
      },
    }))

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

  function handleLimitChange(limit: number) {
    if (isNaN(Number(limit))) {
      setSearchForm((prev) => ({
        ...prev,
        params: {
          ...prev.params,
          page: 1,
          limit: PaginationConstant.MIN_DATA_PER_PAGE,
        },
      }))

      return router.push(
        constructSearchURL('/affiliate-levels', {
          ...searchForm.params,
          page: 1,
          limit: PaginationConstant.MIN_DATA_PER_PAGE,
        }),
      )
    }

    limit =
      Number(limit) < PaginationConstant.MIN_DATA_PER_PAGE ||
      Number(limit) > PaginationConstant.MAX_DATA_PER_PAGE
        ? PaginationConstant.MIN_DATA_PER_PAGE
        : limit

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

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

  useEffect(() => {
    setIsLoadingInitial(true)

    affiliateLevelServices
      .getAffiliateLevels({
        search: searchParams.get('search') || '',
        page: Number(searchParams.get('page') ?? 1),
        limit: Number(
          searchParams.get('limit') ?? PaginationConstant.MIN_DATA_PER_PAGE,
        ),
      })
      .then((data) => {
        setAffiliateLevels(data as Pagination<AffiliateLevel>)
      })
      .catch(() => {
        toast.error('Failed to load affiliate levels. 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">
          Affiliate Levels
        </h1>
        <p className="font-medium text-slate-500">
          Following are the list of affiliate levels. You can manage them here.
        </p>

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

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

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

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

      <ModalForm
        isOpen={
          modal.isOpened && (modal.type === 'create' || modal.type === 'edit')
        }
        type={modal.type as 'create' | 'edit'}
        isProcessing={modal.processing ?? false}
        form={form}
        onClose={handleCloseModal}
        onSubmit={handleSubmitForm}
      />

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