'use client';

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { useLocale, useTranslations } from 'next-intl';

import { addDays, format } from 'date-fns';
import type { Locale } from 'date-fns';
import { enUS, hu } from 'date-fns/locale';

import type { HomepageCollectionTextFields } from '@/services/homeCollections';

import CompactEventLinkCard from '@/components/events/CompactEventLinkCard';
import { Button } from '@/components/ui/button';
import { getFullSizeImageByKey } from '@/utils/images';

import {
  BirthdayDayItem,
  BirthdayRangeCreator,
  BirthdayRangeDay,
  TimelyProgramItem,
} from '@/types/Birthday';
import { Event } from '@/types/Events';

import SectionHeader from '@/components/home/components/SectionHeader';
import { parseIsoDate } from './birthdayDateUtils';

interface HomepageBirthdayCreatorsClientProps {
  initialDateIso: string;
  preloadedBirthdays: BirthdayRangeDay[];
  preloadedPrograms: TimelyProgramItem[];
  textFields?: HomepageCollectionTextFields | null;
}

const DAY_WINDOW = 30;
const CHIP_WIDTH_PX = 108;
const CHIP_GAP_PX = 9;
const CHIP_STEP_PX = CHIP_WIDTH_PX + CHIP_GAP_PX;
const CHIP_WIDTH_CLASS = 'w-[108px]';
const CHIP_FRAME_CLASS = 'h-[144px] w-[108px]';

const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);

const getDateFnsLocale = (locale: string): Locale =>
  locale.toLowerCase().startsWith('en') ? enUS : hu;

const getDistanceScaleY = (distance: number) => {
  if (distance === 0) return 1;
  if (distance === 1) return 0.92;
  if (distance === 2) return 0.84;
  if (distance === 3) return 0.76;
  return 0.7;
};

const getDistanceOpacity = (distance: number) => {
  if (distance === 0) return 1;
  if (distance === 1) return 0.86;
  if (distance === 2) return 0.72;
  if (distance === 3) return 0.58;
  return 0.44;
};

const getBirthdayImageSrc = (imgKey: string | null) =>
  imgKey ? getFullSizeImageByKey(imgKey) : '/assets/images/user_avatar_placeholder_square.png';

const getBirthdayMetaDateLabel = (
  item: BirthdayRangeCreator,
  selectedDay: BirthdayDayItem | undefined,
  locale: string,
  dateLocale: Locale
) => {
  const place = item.szuletesiHely?.trim();
  const hasBirthDate =
    item.szuletesiEv &&
    item.szuletesiHonap &&
    item.szuletesiNap &&
    item.szuletesiHonap >= 1 &&
    item.szuletesiHonap <= 12 &&
    item.szuletesiNap >= 1 &&
    item.szuletesiNap <= 31;

  if (hasBirthDate) {
    const birthDate = new Date(
      item.szuletesiEv!,
      item.szuletesiHonap! - 1,
      item.szuletesiNap!,
      12,
      0,
      0,
      0
    );
    const birthDateLabel = locale.toLowerCase().startsWith('en')
      ? format(birthDate, 'MMM d, yyyy', { locale: dateLocale })
      : format(birthDate, 'yyyy. MMM d.', { locale: dateLocale });
    return place ? `${place}, ${birthDateLabel}` : birthDateLabel;
  }

  if (selectedDay) {
    return place ? `${place}, ${selectedDay.shortLabel}` : selectedDay.shortLabel;
  }

  return '';
};

const buildDayItems = (
  initialDateIso: string,
  locale: string,
  dateLocale: Locale
): BirthdayDayItem[] => {
  const isEnglish = locale.toLowerCase().startsWith('en');
  const parsed = parseIsoDate(initialDateIso);
  const baseDate = parsed
    ? new Date(parsed.year, parsed.month - 1, parsed.day, 12, 0, 0, 0)
    : new Date();

  return Array.from({ length: DAY_WINDOW * 2 + 1 }, (_, index) => {
    const date = addDays(baseDate, index - DAY_WINDOW);

    return {
      index,
      dateIso: format(date, 'yyyy-MM-dd'),
      shortLabel: isEnglish
        ? format(date, 'MMM d', { locale: dateLocale })
        : format(date, 'MMM d.', { locale: dateLocale }),
      longLabel: isEnglish
        ? format(date, 'MMMM d, yyyy', { locale: dateLocale })
        : format(date, 'yyyy. MMMM d.', { locale: dateLocale }),
      dayNumber: format(date, 'd', { locale: dateLocale }),
      monthShort: format(date, 'MMMM', { locale: dateLocale }),
      weekdayShort: format(date, 'EEEE', { locale: dateLocale }),
    };
  });
};

const mapBirthdayToEventCardItem = (
  item: BirthdayRangeCreator,
  sectionLabel: string,
  birthdayText: string
): Event => {
  const imageUrl = getBirthdayImageSrc(item.imgKey ?? null);
  const eventId = item.id > 0 ? item.id : 0;

  return {
    kezdete: new Date().toISOString(),
    kezdeteDatum: false,
    vege: null,
    vegeDatum: false,
    nev: birthdayText,
    leiras: null,
    infoUrl: null,
    jegyUrl: null,
    szemely: [],
    kepLink: imageUrl,
    kulturalisTipus: null,
    kulturalisAltipus: null,
    esemenyMMATagozat: null,
    esemenyFoTipusa: null,
    id: eventId,
    intezmeny: [],
    category: sectionLabel,
    bgColor: '',
    color: '',
    esemenyKategoria: [
      {
        id: 0,
        nev: sectionLabel,
      },
    ],
    url: `birthday-${eventId}`,
    fokep: null,
  };
};

const BirthdayItem: React.FC<{
  item: BirthdayRangeCreator;
  dateLabel: string;
  birthdayText: string;
  sectionLabel: string;
}> = ({ item, dateLabel, birthdayText, sectionLabel }) => {
  const event = useMemo(
    () => mapBirthdayToEventCardItem(item, sectionLabel, birthdayText),
    [item, sectionLabel, birthdayText]
  );
  const hrefOverride = item.alkotoAzonosito
    ? {
        pathname: '/alkoto/[id]' as const,
        params: { id: item.alkotoAzonosito },
      }
    : undefined;

  return (
    <CompactEventLinkCard
      event={event}
      dateLabel={dateLabel}
      locale="hu"
      openInNewTab={false}
      disableLink={!item.alkotoAzonosito}
      showCategoryBadge={false}
      imageVariant="avatarCircle"
      titleClampLines={3}
      hrefOverride={hrefOverride}
      className="h-auto !border-[#c8b95d] !border-l !bg-[#dfcf6f] hover:border-[#b8a84a] hover:!bg-[#e5d46f]"
    />
  );
};

const ProgramItemCard: React.FC<{ item: TimelyProgramItem }> = ({ item }) => {
  return (
    <CompactEventLinkCard
      event={item.event}
      dateLabel={item.dateLabel}
      locale="hu"
      openInNewTab
      className="border-[#151720]/10"
    />
  );
};

const EmptyProgramsState: React.FC<{ message: string }> = ({ message }) => (
  <div className="border border-[#151720]/12 bg-white p-4 text-sm text-[#151720]/60">{message}</div>
);

const EmptyBirthdaysState: React.FC<{ message: string }> = ({ message }) => (
  <div className="border border-[#151720]/12 bg-[#dfcf6f]/12 p-4 text-sm text-[#151720]/70">
    {message}
  </div>
);

const HomepageBirthdayCreatorsClient: React.FC<HomepageBirthdayCreatorsClientProps> = ({
  initialDateIso,
  preloadedBirthdays,
  preloadedPrograms,
  textFields,
}) => {
  const locale = useLocale();
  const dateLocale = useMemo(() => getDateFnsLocale(locale), [locale]);
  const t = useTranslations('home.timely');
  const dayItems = useMemo(
    () => buildDayItems(initialDateIso, locale, dateLocale),
    [initialDateIso, locale, dateLocale]
  );
  const totalDays = dayItems.length;
  const trackRef = useRef<HTMLDivElement | null>(null);
  const rafRef = useRef<number | null>(null);
  const initializedRef = useRef(false);

  const celebratingLabel = t('sections.celebrating');
  const rememberingLabel = t('sections.remembering');
  const programsLabel = t('sections.programs');
  const emptyProgramsLabel = t('states.emptyPrograms');
  const emptyBirthdaysLabel = t('states.emptyBirthdays');

  const initialIndex = useMemo(() => {
    const foundIndex = dayItems.findIndex((item) => item.dateIso === initialDateIso);
    return foundIndex >= 0 ? foundIndex : DAY_WINDOW;
  }, [dayItems, initialDateIso]);

  const [selectedDayIndex, setSelectedDayIndex] = useState(initialIndex);
  const selectedDay = dayItems[selectedDayIndex] ?? dayItems[initialIndex];
  const selectedDateIso = selectedDay?.dateIso ?? initialDateIso;

  const birthdaysByDate = useMemo(() => {
    const map = new Map<string, BirthdayRangeCreator[]>();

    for (const day of preloadedBirthdays) {
      if (!day?.dateIso) continue;
      map.set(day.dateIso, Array.isArray(day.alkotok) ? day.alkotok : []);
    }

    return map;
  }, [preloadedBirthdays]);

  const selectedBirthdayCreators = useMemo(
    () => birthdaysByDate.get(selectedDateIso) ?? [],
    [birthdaysByDate, selectedDateIso]
  );

  const celebratingItems = useMemo(
    () => selectedBirthdayCreators.filter((item) => !item.elhunyt),
    [selectedBirthdayCreators]
  );

  const rememberingItems = useMemo(
    () => selectedBirthdayCreators.filter((item) => item.elhunyt),
    [selectedBirthdayCreators]
  );

  const getBirthdayDateLabel = useCallback(
    (item: BirthdayRangeCreator) => getBirthdayMetaDateLabel(item, selectedDay, locale, dateLocale),
    [selectedDay, locale, dateLocale]
  );

  const getBirthdayText = useCallback(
    (item: BirthdayRangeCreator) => {
      const name = item.nev.trim();
      const anniversary = item.evfordulo ?? 0;
      const profession = item.szakma?.trim();
      const hasProfession = Boolean(profession);

      if (item.elhunyt) {
        return hasProfession
          ? t('birthdayText.rememberingBorn', {
              anniversary,
              name,
              profession,
            })
          : t('birthdayText.rememberingBornNoProfession', {
              anniversary,
              name,
            });
      }

      return hasProfession
        ? t('birthdayText.celebrating', {
            anniversary,
            name,
            profession,
          })
        : t('birthdayText.celebratingNoProfession', {
            anniversary,
            name,
          });
    },
    [t]
  );

  const programsByDate = useMemo(() => {
    const map = new Map<string, TimelyProgramItem[]>();

    for (const item of preloadedPrograms) {
      const bucket = map.get(item.dateIso);
      if (bucket) {
        bucket.push(item);
      } else {
        map.set(item.dateIso, [item]);
      }
    }

    map.forEach((items) => {
      items.sort((a, b) => {
        const aTime = new Date(a.event.kezdete).getTime();
        const bTime = new Date(b.event.kezdete).getTime();
        if (aTime !== bTime) return aTime - bTime;
        return a.id.localeCompare(b.id);
      });
    });

    return map;
  }, [preloadedPrograms]);

  const selectedPrograms = useMemo(
    () => programsByDate.get(selectedDateIso) ?? [],
    [programsByDate, selectedDateIso]
  );

  const [leftPrograms, rightPrograms] = useMemo(() => {
    const left: TimelyProgramItem[] = [];
    const right: TimelyProgramItem[] = [];

    selectedPrograms.forEach((item, index) => {
      if (index % 2 === 0) {
        left.push(item);
      } else {
        right.push(item);
      }
    });

    return [left, right];
  }, [selectedPrograms]);

  const syncSelectedFromScroll = useCallback(
    (element: HTMLDivElement) => {
      const nextIndex = clamp(
        Math.round(element.scrollLeft / CHIP_STEP_PX),
        0,
        Math.max(totalDays - 1, 0)
      );
      setSelectedDayIndex((prev) => (prev === nextIndex ? prev : nextIndex));
    },
    [totalDays]
  );

  const handleTrackScroll = () => {
    const element = trackRef.current;
    if (!element || rafRef.current !== null) return;

    rafRef.current = window.requestAnimationFrame(() => {
      rafRef.current = null;
      syncSelectedFromScroll(element);
    });
  };

  useEffect(() => {
    const element = trackRef.current;
    if (!element || initializedRef.current) return;

    initializedRef.current = true;
    element.scrollLeft = initialIndex * CHIP_STEP_PX;
    syncSelectedFromScroll(element);
  }, [initialIndex, syncSelectedFromScroll]);

  useEffect(() => {
    return () => {
      if (rafRef.current !== null) {
        window.cancelAnimationFrame(rafRef.current);
      }
    };
  }, []);

  const scrollToIndex = (nextIndex: number, smooth: boolean = true) => {
    const element = trackRef.current;
    if (!element) return;

    const bounded = clamp(nextIndex, 0, Math.max(totalDays - 1, 0));
    element.scrollTo({
      left: bounded * CHIP_STEP_PX,
      behavior: smooth ? 'smooth' : 'auto',
    });
  };

  const shiftBy = (delta: number) => {
    scrollToIndex(selectedDayIndex + delta, true);
  };

  return (
    <section className="relative w-full overflow-hidden bg-white px-site py-14 text-[#151720] sm:py-16 lg:py-20">
      <div className="pointer-events-none absolute inset-0" />
      <div className="pointer-events-none absolute inset-0 opacity-20 bg-[linear-gradient(90deg,rgba(15,23,42,0.08)_1px,transparent_1px),linear-gradient(0deg,rgba(15,23,42,0.08)_1px,transparent_1px)] bg-[size:52px_52px]" />

      <div className="relative mx-auto max-w-boxed space-y-8">
        <SectionHeader
          eyebrow={textFields?.blockLabel || ''}
          eyebrowUrl="/programok"
          title={textFields?.blockTitle || ''}
          description={textFields?.blockSubtitle || ''}
          maxWidth
        />

        <div className="space-y-3">
          <div className="hidden items-center justify-end gap-2 sm:flex">
            <Button
              type="button"
              variant="outline"
              size="icon"
              aria-label={t('controls.previousDay')}
              onClick={() => shiftBy(-1)}
              disabled={selectedDayIndex <= 0}
            >
              {'\u2190'}
            </Button>
            <Button
              type="button"
              variant="outline"
              size="icon"
              aria-label={t('controls.nextDay')}
              onClick={() => shiftBy(1)}
              disabled={selectedDayIndex >= totalDays - 1}
            >
              {'\u2192'}
            </Button>
          </div>

          <div className="relative mx-auto w-full max-w-[860px] overflow-hidden bg-white">
            <div className="pointer-events-none absolute inset-y-0 left-0 z-10 w-[108px] bg-gradient-to-r from-white via-white/96 to-transparent sm:w-[156px] lg:w-[210px]" />
            <div className="pointer-events-none absolute inset-y-0 right-0 z-10 w-[108px] bg-gradient-to-l from-white via-white/96 to-transparent sm:w-[156px] lg:w-[210px]" />
            <div className="pointer-events-none absolute inset-y-0 left-1/2 z-20 -translate-x-1/2">
              <div
                className="h-full border border-[#dfcf6f]/80 bg-gradient-to-b from-[#dfcf6f]/12 via-[#dfcf6f]/10 to-[#dfcf6f]/12 shadow-[0_0_0_1px_rgba(223,207,111,0.45),0_24px_34px_-26px_rgba(223,207,111,0.95)]"
                style={{ width: `${CHIP_WIDTH_PX + 2}px` }}
              />
            </div>

            <div
              ref={trackRef}
              onScroll={handleTrackScroll}
              className="no-scrollbar relative z-10 flex snap-x snap-mandatory items-center overflow-x-auto"
              style={{
                gap: `${CHIP_GAP_PX}px`,
                paddingLeft: `calc(50% - ${CHIP_WIDTH_PX / 2}px)`,
                paddingRight: `calc(50% - ${CHIP_WIDTH_PX / 2}px)`,
              }}
            >
              {dayItems.map((item) => {
                const isActive = item.index === selectedDayIndex;
                const distance = Math.abs(item.index - selectedDayIndex);
                const scaleY = getDistanceScaleY(distance);
                const opacity = getDistanceOpacity(distance);

                return (
                  <button
                    key={item.dateIso}
                    type="button"
                    onClick={() => scrollToIndex(item.index)}
                    style={{
                      opacity,
                      zIndex: Math.max(1, 30 - distance),
                    }}
                    className={`snap-center ${CHIP_FRAME_CLASS} ${CHIP_WIDTH_CLASS} shrink-0 transition-[opacity] duration-150`}
                    aria-label={item.longLabel}
                    aria-pressed={isActive}
                  >
                    <div
                      style={{
                        transform: `scaleY(${scaleY})`,
                        transformOrigin: 'center center',
                      }}
                      className={`flex h-full w-full flex-col items-center justify-center border transition-[transform,border-color,background-color,color] duration-150 ${
                        isActive
                          ? 'border-transparent bg-gradient-to-b from-[#151720]/10 to-[#151720]/3 text-[#151720]'
                          : 'border-[#151720]/18 bg-gradient-to-b from-[#151720]/[0.04] to-[#151720]/[0.01] text-[#151720]/50 hover:border-[#151720]/35 hover:from-[#151720]/[0.08] hover:to-[#151720]/[0.03] hover:text-[#151720]'
                      }`}
                    >
                      <span
                        className={`text-xs uppercase font-bold tracking-[0.14em] ${
                          isActive ? 'text-[#a5952c]' : 'text-[#151720]/40'
                        }`}
                      >
                        {item.monthShort}
                      </span>
                      <span className="mt-1 text-[48px] font-semibold leading-none">
                        {item.dayNumber}
                      </span>
                      <span className="mt-1 text-[11px] uppercase tracking-[0.1em] font-bold text-[#151720]/60">
                        {item.weekdayShort}
                      </span>
                    </div>
                  </button>
                );
              })}
            </div>
          </div>
        </div>

        <div className="grid items-start gap-6 lg:grid-cols-3 lg:gap-5">
          <div className="lg:col-span-1">
            <section className="space-y-3 lg:hidden">
              <p className="type-eyebrow text-[#151720]/60">{programsLabel}</p>
              {selectedPrograms.length === 0 && <EmptyProgramsState message={emptyProgramsLabel} />}
              {selectedPrograms.map((item) => (
                <ProgramItemCard key={item.id} item={item} />
              ))}
            </section>

            <div className="mt-6 space-y-6 lg:mt-0">
              {celebratingItems.length === 0 && rememberingItems.length === 0 ? (
                <EmptyBirthdaysState message={emptyBirthdaysLabel} />
              ) : (
                <>
                  {celebratingItems.length > 0 && (
                    <section>
                      <p className="type-eyebrow mb-3 text-[#151720]/60 sm:mb-3">
                        {celebratingLabel}
                      </p>
                      <div className="space-y-2.5">
                        {celebratingItems.map((item) => (
                          <BirthdayItem
                            key={`living-${item.id}`}
                            item={item}
                            dateLabel={getBirthdayDateLabel(item)}
                            birthdayText={getBirthdayText(item)}
                            sectionLabel={celebratingLabel}
                          />
                        ))}
                      </div>
                    </section>
                  )}

                  {rememberingItems.length > 0 && (
                    <section>
                      <p className="type-eyebrow mb-3 text-[#151720]/60 sm:mb-3">
                        {rememberingLabel}
                      </p>
                      <div className="space-y-2.5">
                        {rememberingItems.map((item) => (
                          <BirthdayItem
                            key={`remembering-${item.id}`}
                            item={item}
                            dateLabel={getBirthdayDateLabel(item)}
                            birthdayText={getBirthdayText(item)}
                            sectionLabel={rememberingLabel}
                          />
                        ))}
                      </div>
                    </section>
                  )}
                </>
              )}
            </div>
          </div>

          <div className="hidden space-y-3 lg:block">
            <p className="type-eyebrow mb-3 text-[#151720]/60 sm:mb-3">{programsLabel}</p>
            {selectedPrograms.length === 0 && <EmptyProgramsState message={emptyProgramsLabel} />}
            {leftPrograms.map((item) => (
              <ProgramItemCard key={item.id} item={item} />
            ))}
          </div>

          <div className="hidden space-y-3 lg:block">
            <p className="type-eyebrow invisible mb-3 sm:mb-3">{programsLabel}</p>
            {rightPrograms.map((item) => (
              <ProgramItemCard key={item.id} item={item} />
            ))}
          </div>
        </div>
      </div>
    </section>
  );
};

export default HomepageBirthdayCreatorsClient;
