import { useMemo, useState } from 'react';

import { useRouter } from 'next/navigation';

import { formatCurrency } from '@/packages/shared/src/utils';
import { addHours, isAfter, isSameDay } from 'date-fns';
import { orderBy } from 'lodash';
import { useTranslation } from 'react-i18next';

import { pathsConfig } from '@kit/shared/config';
import { formatDateAndTime } from '@kit/shared/utils';
import { Button } from '@kit/ui/shadcn/button';
import { Card } from '@kit/ui/shadcn/card';
import { toast } from '@kit/ui/sonner';
import { Trans } from '@kit/ui/trans';
import { cn } from '@kit/ui/utils';

import { updateReservationTime } from '~/lib/services/reservation.service';

import { createInitialReservationAction } from '../../_lib/server/actions';
import { EnrichedCartItem } from '../cart/types';
import { ServiceProvider, TimeSlot } from './booking.context';
import { useBooking } from './booking.provider';

const getServiceProviderTitle = (
  currentLocale: string,
  serviceProvider?: ServiceProvider,
) => {
  if (!serviceProvider) return null;
  if (currentLocale === 'en') return serviceProvider.jobTitleEn;
  if (currentLocale === 'ru') return serviceProvider.jobTitleRu;

  return serviceProvider.jobTitleEt;
};

const PAGE_SIZE = 7;

const TimeSlots = ({
  countryCode,
  cartItem,
  onComplete,
}: {
  countryCode: string;
  cartItem?: EnrichedCartItem;
  onComplete?: () => void;
}) => {
  const [currentPage, setCurrentPage] = useState(1);

  const {
    t,
    i18n: { language: currentLocale },
  } = useTranslation();

  const booking = useBooking();

  const router = useRouter();

  const selectedDate = booking.selectedDate ?? new Date();

  const filteredBookings = useMemo(
    () =>
      orderBy(
        booking?.timeSlots?.filter(({ StartTime }) => {
          const firstAvailableTimeToSelect = isSameDay(selectedDate, new Date())
            ? addHours(new Date(), 0.5)
            : selectedDate;
          return isAfter(StartTime, firstAvailableTimeToSelect);
        }) ?? [],
        'StartTime',
        'asc',
      ),
    [booking.timeSlots, selectedDate],
  );

  const totalPages = Math.ceil(filteredBookings.length / PAGE_SIZE);

  const paginatedBookings = useMemo(() => {
    const startIndex = (currentPage - 1) * PAGE_SIZE;
    const endIndex = startIndex + PAGE_SIZE;
    return filteredBookings.slice(startIndex, endIndex);
  }, [filteredBookings, currentPage, PAGE_SIZE]);

  const handlePageChange = (page: number) => {
    setCurrentPage(page);
  };

  const generatePageNumbers = () => {
    const pages = [];
    const maxVisiblePages = 5;

    if (totalPages <= maxVisiblePages) {
      for (let i = 1; i <= totalPages; i++) {
        pages.push(i);
      }
    } else {
      if (currentPage <= 3) {
        for (let i = 1; i <= 4; i++) {
          pages.push(i);
        }
        pages.push('...');
        pages.push(totalPages);
      } else if (currentPage >= totalPages - 2) {
        pages.push(1);
        pages.push('...');
        for (let i = totalPages - 3; i <= totalPages; i++) {
          pages.push(i);
        }
      } else {
        pages.push(1);
        pages.push('...');
        for (let i = currentPage - 1; i <= currentPage + 1; i++) {
          pages.push(i);
        }
        pages.push('...');
        pages.push(totalPages);
      }
    }

    return pages;
  };

  if (!booking?.timeSlots?.length) {
    return null;
  }

  const handleBookTime = async (timeSlot: TimeSlot, comments?: string) => {
    const selectedService = booking.selectedService;

    const selectedVariant = selectedService?.variants?.[0];

    const syncedService = timeSlot.syncedService;
    if (!syncedService || !selectedVariant) {
      return toast.error(t('booking:serviceNotFound'));
    }

    const bookTimePromise = createInitialReservationAction(
      selectedVariant,
      countryCode,
      Number(syncedService.id),
      syncedService?.clinic_id,
      timeSlot.UserID,
      timeSlot.SyncUserID,
      timeSlot.StartTime,
      booking.selectedLocationId ? booking.selectedLocationId : null,
      comments,
    ).then(() => {
      if (onComplete) {
        onComplete();
      }
      router.push(pathsConfig.app.cart);
    });

    toast.promise(() => bookTimePromise, {
      success: <Trans i18nKey={'booking:bookTimeSuccess'} />,
      error: <Trans i18nKey={'booking:bookTimeError'} />,
      loading: <Trans i18nKey={'booking:bookTimeLoading'} />,
    });
  };

  const handleChangeTime = async (
    timeSlot: TimeSlot,
    reservationId: number,
    cartId: string,
  ) => {
    const syncedService = timeSlot.syncedService;
    if (!syncedService) {
      return toast.error(t('booking:serviceNotFound'));
    }

    const bookTimePromise = updateReservationTime(
      reservationId,
      timeSlot.StartTime,
      Number(syncedService.id),
      timeSlot.UserID,
      timeSlot.SyncUserID,
      booking.selectedLocationId ? booking.selectedLocationId : null,
      cartId,
    );

    toast.promise(() => bookTimePromise, {
      success: <Trans i18nKey={'booking:bookTimeSuccess'} />,
      error: <Trans i18nKey={'booking:bookTimeError'} />,
      loading: <Trans i18nKey={'booking:bookTimeLoading'} />,
    });

    if (onComplete) {
      onComplete();
    }
  };

  const handleTimeSelect = async (timeSlot: TimeSlot) => {
    if (cartItem?.reservation.id) {
      return handleChangeTime(
        timeSlot,
        cartItem.reservation.id,
        cartItem.cart_id,
      );
    }

    return handleBookTime(timeSlot);
  };

  return (
    <div className="flex w-full flex-col gap-4">
      <div className="flex h-full w-full flex-col gap-2 overflow-auto">
        {paginatedBookings.map((timeSlot, index) => {
          const isEHIF = timeSlot.HKServiceID > 0;
          const serviceProviderTitle = getServiceProviderTitle(
            currentLocale,
            timeSlot.serviceProvider,
          );
          const price =
            booking.selectedService?.variants?.[0]?.calculated_price
              ?.calculated_amount ?? cartItem?.unit_price;
          return (
            <Card
              className="xs:flex xs:justify-between grid w-full justify-center-safe gap-3 p-4"
              key={index}
            >
              <div>
                <span>{formatDateAndTime(timeSlot.StartTime.toString())}</span>
                <div className="flex">
                  <h5
                    className={cn(
                      (serviceProviderTitle || isEHIF) &&
                        "after:mx-2 after:content-['·']",
                    )}
                  >
                    {timeSlot.serviceProvider?.name}
                  </h5>
                  {serviceProviderTitle && (
                    <span
                      className={cn(isEHIF && "after:mx-2 after:content-['·']")}
                    >
                      {serviceProviderTitle}
                    </span>
                  )}
                  {isEHIF && <span>{t('booking:ehifBooking')}</span>}
                </div>
                <div className="flex text-xs">{timeSlot.location?.address}</div>
              </div>
              <div className="flex-end not-last:xs:justify-center flex items-center justify-between gap-2">
                <span className="text-sm font-semibold">
                  {formatCurrency({
                    currencyCode: 'EUR',
                    locale: 'et-EE',
                    value: price ?? '',
                  })}
                </span>
                <Button onClick={() => handleTimeSelect(timeSlot)} size="sm">
                  <Trans i18nKey="common:book" />
                </Button>
              </div>
            </Card>
          );
        })}

        {!paginatedBookings.length && (
          <div className="wrap text-muted-foreground flex size-full content-center-safe justify-center-safe">
            <p>{t('booking:noResults')}</p>
          </div>
        )}
      </div>

      {totalPages > 1 && (
        <div className="flex items-center justify-between">
          <div className="text-muted-foreground text-sm">
            {t('common:pageOfPages', {
              page: currentPage,
              total: totalPages,
            })}
          </div>

          <div className="flex items-center gap-1">
            <Button
              variant="outline"
              size="sm"
              onClick={() => handlePageChange(currentPage - 1)}
              disabled={currentPage === 1}
            >
              <Trans i18nKey="common:previous" defaultValue="Previous" />
            </Button>

            {generatePageNumbers().map((page, index) => (
              <Button
                key={index}
                variant={page === currentPage ? 'default' : 'outline'}
                size="sm"
                onClick={() =>
                  typeof page === 'number' && handlePageChange(page)
                }
                disabled={page === '...'}
                className={cn(
                  'min-w-[2rem]',
                  page === '...' && 'cursor-default hover:bg-transparent',
                )}
              >
                {page}
              </Button>
            ))}

            <Button
              variant="outline"
              size="sm"
              onClick={() => handlePageChange(currentPage + 1)}
              disabled={currentPage === totalPages}
            >
              <Trans i18nKey="common:next" defaultValue="Next" />
            </Button>
          </div>
        </div>
      )}
    </div>
  );
};

export default TimeSlots;
