import {
  memo, useMemo,
} from '../../../lib/teact/teact';

import type { ApiBusinessWorkHours } from '../../../api/types';

import { selectTimezones } from '../../../global/selectors';
import {
  VTT_PROFILE_BUSINESS_HOURS,
} from '../../../util/animations/viewTransitionTypes';
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
import buildClassName from '../../../util/buildClassName';
import { formatTime, formatWeekday } from '../../../util/dates/oldDateFormat';
import {
  getUtcOffset, getWeekStart, shiftTimeRanges, splitDays,
} from '../../../util/dates/workHours';

import { useViewTransition } from '../../../hooks/animations/useViewTransition';
import { useVtn } from '../../../hooks/animations/useVtn';
import { useSelectorSignal } from '../../../hooks/data/useSelector';
import useInterval from '../../../hooks/schedulers/useInterval';
import useDerivedState from '../../../hooks/useDerivedState';
import useFlag from '../../../hooks/useFlag';
import useForceUpdate from '../../../hooks/useForceUpdate';
import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';

import ListItem from '../../ui/ListItem';
import Icon from '../icons/Icon';

import styles from './BusinessHours.module.scss';

const DAYS = Array.from({ length: 7 }, (_, i) => i);

type OwnProps = {
  businessHours: ApiBusinessWorkHours;
  className?: string;
};

const BusinessHours = ({
  businessHours,
  className,
}: OwnProps) => {
  const [isExpanded, expand, collapse] = useFlag(false);
  const [isMyTime, showInMyTime, showInLocalTime] = useFlag(false);
  const oldLang = useOldLang();
  const forceUpdate = useForceUpdate();

  const { startViewTransition } = useViewTransition();
  const { createVtnStyle } = useVtn();

  useInterval(forceUpdate, 60 * 1000);

  const timezoneSignal = useSelectorSignal(selectTimezones);
  const timezones = useDerivedState(timezoneSignal, [timezoneSignal]);
  const timezoneMinuteDifference = useMemo(() => {
    if (!timezones) return 0;
    const timezone = timezones[businessHours.timezoneId];
    const myOffset = getUtcOffset();
    return (myOffset - timezone.utcOffset) / 60;
  }, [businessHours.timezoneId, timezones]);

  const workHours = useMemo(() => {
    const weekStart = getWeekStart();
    const shiftedHours = shiftTimeRanges(businessHours.workHours, isMyTime ? timezoneMinuteDifference : 0);
    const days = splitDays(shiftedHours);
    const result: Record<number, string[]> = {};

    DAYS.forEach((day) => {
      const segments = days[day];
      if (!segments) {
        result[day] = [oldLang('BusinessHoursDayClosed')];
        return;
      }

      result[day] = segments.map(({ startMinute, endMinute }) => {
        if (endMinute - startMinute === 24 * 60) return oldLang('BusinessHoursDayFullOpened');
        const start = formatTime(oldLang, weekStart + startMinute * 60 * 1000);
        const end = formatTime(oldLang, weekStart + endMinute * 60 * 1000);
        return `${start} – ${end}`;
      });
    });

    return result;
  }, [businessHours.workHours, isMyTime, oldLang, timezoneMinuteDifference]);

  const isBusinessOpen = useMemo(() => {
    const localTimeHours = shiftTimeRanges(businessHours.workHours, timezoneMinuteDifference);

    const weekStart = getWeekStart();
    const now = new Date().getTime();
    const minutesSinceWeekStart = (now - weekStart) / 1000 / 60;

    return localTimeHours.some(({ startMinute, endMinute }) => (
      startMinute <= minutesSinceWeekStart && minutesSinceWeekStart <= endMinute
    ));
  }, [businessHours.workHours, timezoneMinuteDifference]);

  const currentDay = useMemo(() => {
    const now = new Date(Date.now() - (isMyTime ? 0 : timezoneMinuteDifference * 60 * 1000));
    return (now.getDay() + 6) % 7;
  }, [isMyTime, timezoneMinuteDifference]);

  const handleClick = useLastCallback(() => {
    if (isExpanded) {
      collapse();
    } else {
      expand();
    }
  });

  const handleTriggerOffset = useLastCallback((e: React.MouseEvent) => {
    e.stopPropagation();

    startViewTransition(VTT_PROFILE_BUSINESS_HOURS, () => {
      if (isMyTime) {
        showInLocalTime();
      } else {
        showInMyTime();
      }
    });
  });

  return (
    <ListItem
      icon="clock"
      iconClassName={styles.icon}
      multiline
      className={buildClassName(styles.root, className)}
      style={createVtnStyle('businessHours', true)}
      isStatic={isExpanded}
      ripple
      narrow
      withColorTransition
      onClick={handleClick}
    >
      <div className={styles.top}>
        <div className={styles.left}>
          <div>{oldLang('BusinessHoursProfile')}</div>
          <div
            className={buildClassName(styles.status, isBusinessOpen && styles.statusOpen)}
          >
            {isBusinessOpen ? oldLang('BusinessHoursProfileNowOpen') : oldLang('BusinessHoursProfileNowClosed')}
          </div>
        </div>
        <Icon className={styles.arrow} style={createVtnStyle('expandArrow', true)} name={isExpanded ? 'up' : 'down'} />
      </div>
      <div className={buildClassName(styles.bottom, !isExpanded && styles.collapsed)} aria-hidden={!isExpanded}>
        {Boolean(timezoneMinuteDifference) && (
          <div
            className={styles.offsetTrigger}
            style={createVtnStyle('offsetTrigger')}
            role="button"
            tabIndex={isExpanded ? 0 : -1}
            onMouseDown={!IS_TOUCH_ENV ? handleTriggerOffset : undefined}
            onClick={IS_TOUCH_ENV ? handleTriggerOffset : undefined}
          >
            {oldLang(isMyTime ? 'BusinessHoursProfileSwitchMy' : 'BusinessHoursProfileSwitchLocal')}
          </div>
        )}
        <dl className={styles.timetable}>
          {DAYS.map((day) => (
            <>
              <dt className={buildClassName(styles.weekday, day === currentDay && styles.currentDay)}>
                {formatWeekday(oldLang, day === 6 ? 0 : day + 1)}
              </dt>
              <dd className={styles.schedule}>
                {workHours[day].map((segment) => (
                  <div>{segment}</div>
                ))}
              </dd>
            </>
          ))}
        </dl>
      </div>
    </ListItem>
  );
};

export default memo(BusinessHours);
