import { TravelPartner } from '@/lib/types/partner'
import formTheme from '@/lib/themes/form'
import { Label } from 'flowbite-react'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import InputWithClearButton from './InputWithClearButton'
import Combobox from '../Combobox'
import {
  getTravelPartner,
  getTravelPartners,
} from '@/lib/services/travel-partner-services'
import { toast } from 'react-toastify'
import { paginationDefaultData } from '@/lib/data/pagination'
import * as PaginationConstant from '@/lib/constants/pagination'

interface PartnerSelectorProps {
  selectedPartnerId?: number
  fullWidth?: boolean
  onSelectPartner?: (partner: TravelPartner | null) => void
}

function getPartnerName(partner: TravelPartner): string {
  return partner.business?.business_name ?? partner.driver?.name ?? ''
}

function getPartnerEmail(partner: TravelPartner): string {
  return partner.business?.business_email ?? partner.driver?.email ?? ''
}

const PartnerSelector: React.FC<PartnerSelectorProps> = ({
  selectedPartnerId,
  fullWidth = false,
  onSelectPartner,
}) => {
  const [showPartnerDropdown, setShowPartnerDropdown] = useState(false)
  const [partnerSearchValue, setPartnerSearchValue] = useState('')
  const [debouncedSearch, setDebouncedSearch] = useState('')
  const partnerInputRef = useRef<HTMLInputElement>(null)
  const partnerContainerRef = useRef<HTMLDivElement>(null)
  const [partners, setPartners] = useState<Pagination<TravelPartner>>(
    paginationDefaultData,
  )
  const [selectedPartner, setSelectedPartner] = useState<TravelPartner | null>(
    null,
  )
  const [loadingPartners, setLoadingPartners] = useState(true)
  const [isLoadingMore, setIsLoadingMore] = useState(false)

  const hasMore = useMemo(
    () =>
      !!partners.next_page_url && partners.current_page < partners.last_page,
    [partners],
  )

  // Debounce search input for API calls
  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedSearch(partnerSearchValue)
    }, 300)

    return () => clearTimeout(timer)
  }, [partnerSearchValue])

  // Fetch partners (initial + on search change)
  useEffect(() => {
    async function fetchPartners() {
      setLoadingPartners(true)

      try {
        const data = (await getTravelPartners({
          page: 1,
          limit: PaginationConstant.MIN_DATA_PER_PAGE,
          search: debouncedSearch,
        })) as Pagination<TravelPartner>
        setPartners(data)
      } catch {
        toast.error('Error fetching travel partners. Please try again.')
      } finally {
        setLoadingPartners(false)
      }
    }

    fetchPartners()
  }, [debouncedSearch])

  // Load more pages for infinite scroll
  const loadMore = useCallback(async () => {
    if (isLoadingMore || !hasMore) return

    setIsLoadingMore(true)

    try {
      const updatedPartners = (await getTravelPartners({
        page: partners.current_page + 1,
        limit: PaginationConstant.MIN_DATA_PER_PAGE,
        search: debouncedSearch,
      })) as Pagination<TravelPartner>

      setPartners((prev) => ({
        ...updatedPartners,
        data: [...prev.data, ...updatedPartners.data],
      }))
    } finally {
      setIsLoadingMore(false)
    }
  }, [partners, hasMore, isLoadingMore, debouncedSearch])

  // Auto-select partner when selectedPartnerId is provided
  useEffect(() => {
    if (!selectedPartnerId) {
      setSelectedPartner(null)
      return
    }

    // Check if already selected
    if (selectedPartner && selectedPartner.id === selectedPartnerId) {
      return
    }

    // Check if partner exists in loaded list
    const matched = partners.data.find(
      (partner) => partner.id === selectedPartnerId,
    )
    if (matched) {
      setSelectedPartner(matched)
      return
    }

    // Fetch the specific partner by ID if not in loaded list
    if (!loadingPartners) {
      getTravelPartner(selectedPartnerId).then(setSelectedPartner)
    }
  }, [selectedPartnerId, partners.data, loadingPartners, selectedPartner])

  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      if (
        partnerContainerRef.current &&
        !partnerContainerRef.current.contains(event.target as Node)
      ) {
        setShowPartnerDropdown(false)
        setPartnerSearchValue('')
      }
    }

    document.addEventListener('mousedown', handleClickOutside)
    return () => {
      document.removeEventListener('mousedown', handleClickOutside)
    }
  }, [])

  function handlePartnerSelect(partner: TravelPartner) {
    setSelectedPartner(partner)
    onSelectPartner?.(partner)

    setShowPartnerDropdown(false)
    setPartnerSearchValue('')
  }

  function handlePartnerSearch(e: React.ChangeEvent<HTMLInputElement>) {
    setPartnerSearchValue(e.target.value)
  }

  function handlePartnerInputClick() {
    setShowPartnerDropdown(true)

    // Focus on the search input after dropdown opens
    setTimeout(() => {
      partnerInputRef.current?.focus()
    }, 100)
  }

  function handleClearPartner() {
    setSelectedPartner(null)
    onSelectPartner?.(null)

    setPartnerSearchValue('')
  }

  return (
    <div className="w-full relative">
      <div className="block mb-2">
        <Label htmlFor="partner" theme={formTheme.label}>
          Travel Partner
        </Label>
      </div>

      <div className="relative" ref={partnerContainerRef}>
        <InputWithClearButton
          id="partner"
          className={`w-full ${fullWidth ? '' : 'max-w-96'} cursor-pointer`}
          placeholder="Select a travel partner..."
          value={selectedPartner ? getPartnerName(selectedPartner) : ''}
          onClick={handlePartnerInputClick}
          onClear={handleClearPartner}
          readOnly
          showClearButton={!!selectedPartner}
        />

        <Combobox
          showDropdown={showPartnerDropdown}
          searchValue={partnerSearchValue}
          placeholderText="Search travel partners..."
          inputRef={partnerInputRef as React.RefObject<HTMLInputElement>}
          isLoading={loadingPartners}
          filteredOptions={partners.data}
          selectedOption={selectedPartner as TravelPartner}
          options={partners.data}
          handleSelectOption={handlePartnerSelect}
          handleSearch={handlePartnerSearch}
          hasMore={hasMore}
          isLoadingMore={isLoadingMore}
          onLoadMore={loadMore}
          renderLoadingMore={() => <span>Loading more travel partners...</span>}
          renderOption={(partner) => (
            <div
              key={partner.id}
              className="p-3 hover:bg-gray-50 cursor-pointer border-b border-gray-100 last:border-b-0"
              onClick={() => handlePartnerSelect(partner)}
            >
              <div className="font-medium text-gray-900">
                {getPartnerName(partner)}
              </div>
              <div className="text-sm text-gray-500">
                {getPartnerEmail(partner)}
              </div>
            </div>
          )}
          renderNoResultsFound={() => (
            <div className="p-3 text-center text-gray-500">
              No travel partners found
            </div>
          )}
          renderSkeletonComponent={() =>
            Array.from({ length: 5 }).map((_, index) => (
              <div
                key={index}
                className="p-3 border-b border-gray-100 last:border-b-0 animate-pulse"
              >
                <div className="h-4 bg-gray-200 rounded w-3/4 mb-2"></div>
                <div className="h-3 bg-gray-200 rounded w-1/2"></div>
              </div>
            ))
          }
        />
      </div>
    </div>
  )
}

export default PartnerSelector
