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 { Skeleton } from '@kit/ui/shadcn/skeleton';
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 BookingPagination from './booking-pagination';
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',
      ).filter(({ StartTime }) => isSameDay(StartTime, selectedDate)),
    [booking.timeSlots, selectedDate],
  );

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

  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);
      })
      .catch((error) => {
        console.error('Booking error: ', error);
        throw error;
      });

    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,
      newStartTime: timeSlot.StartTime,
      newServiceId: Number(syncedService.id),
      newAppointmentUserId: timeSlot.UserID,
      newSyncUserId: timeSlot.SyncUserID,
      newLocationId: 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 (
    <Skeleton
      isLoading={booking.isLoadingTimeSlots}
      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 isHaigeKassa = 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 || isHaigeKassa) &&
                        "after:mx-2 after:content-['·']",
                    )}
                  >
                    {timeSlot.serviceProvider?.name}
                  </h5>
                  {serviceProviderTitle && (
                    <span
                      className={cn(
                        isHaigeKassa && "after:mx-2 after:content-['·']",
                      )}
                    >
                      {serviceProviderTitle}
                    </span>
                  )}
                  {isHaigeKassa && <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>
          );
        })}
      </div>

      <BookingPagination
        totalPages={Math.ceil(filteredBookings.length / PAGE_SIZE)}
        setCurrentPage={setCurrentPage}
        currentPage={currentPage}
      />
    </Skeleton>
  );
};

export default TimeSlots;
