import { Box, SxProps, Tooltip, TooltipProps } from '@mui/material';
import { useEffect, useMemo } from 'react';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import relativeTime from 'dayjs/plugin/relativeTime';
import updateLocale from 'dayjs/plugin/updateLocale';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import { create } from 'zustand';
import { formatToDatetime, setDateTool } from '../Util';
import type { Locale } from '../type';

dayjs.extend(localizedFormat);
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(updateLocale);
dayjs.extend(relativeTime);
dayjs.updateLocale('zh-cn', {
  // copy with https://github.com/iamkun/dayjs/blob/dev/src/locale/zh-cn.js
  relativeTime: {
    future: '%s后',
    past: '%s前',
    s: '几秒',
    m: '1 分钟',
    mm: '%d 分钟',
    h: '1 小时',
    hh: '%d 小时',
    d: '1 天',
    dd: '%d 天',
    M: '1 个月',
    MM: '%d 个月',
    y: '1 年',
    yy: '%d 年',
  },
});
// FIXME: @zhanghan 此处不能真正的将 relativeTime 设置为支持中文
setDateTool(dayjs);

const translations: Record<Locale, { utc: string; local: string; shortUTC: string; shortLocal: string }> = {
  en: {
    utc: 'UTC Timezone',
    local: 'Local Timezone',
    shortUTC: 'UTC',
    shortLocal: 'Local',
  },
  zh: {
    utc: 'UTC 时区',
    local: '当前时区',
    shortUTC: 'UTC',
    shortLocal: '当前时区',
  },
};

type UtcState = { isUtc: boolean; setIsUtc: (isUtc: boolean) => void };
const useUtcStore = create<UtcState>((set) => ({
  isUtc: false,
  setIsUtc: (isUtc: boolean) => set({ isUtc }),
}));

export interface RelativeTimeProps {
  value: string | number;
  locale?: Locale;
  withoutSuffix?: false | true;
  from?: string | number;
  to?: string | number;
  type?: 'relative' | 'absolute' | 'utc' | 'all';
  tz?: string;
  relativeRange?: number;
  enableTooltip?: boolean;
  useShortTimezone?: boolean;
  disableTimezone?: boolean;
  placement?: TooltipProps['placement'];
  sx?: SxProps;
  format?: string;
  mode?: 'all' | 'daysLeft'; // all: 显示所有内容，daysLeft: 只显示剩余天数
}

function normalizeTimestamp(value: string | number) {
  let normalizedValue = value;
  if (typeof normalizedValue === 'string' && /^\d+$/.test(normalizedValue)) {
    normalizedValue = Number(normalizedValue);
  }

  if (typeof normalizedValue === 'number') {
    // 10 位左右：很可能是秒（例如 1699411200）
    // 13 位左右：很可能是毫秒（例如 1699411200000）
    const abs = Math.abs(Math.trunc(normalizedValue));
    // < 100,000,000,000 -> treat as seconds (safe threshold for seconds)
    if (abs < 1e11) {
      return new Date(normalizedValue * 1000).getTime();
    }

    return new Date(normalizedValue).getTime();
  }

  return new Date(normalizedValue).getTime();
}

function useRelativeTime({
  value,
  locale = 'en',
  withoutSuffix = false,
  from = '',
  to = '',
  type = 'relative',
  tz,
  relativeRange,
  format,
}: {
  value: string | number;
  locale?: Locale;
  withoutSuffix?: boolean;
  from?: string | number;
  to?: string | number;
  type?: 'relative' | 'absolute' | 'utc';
  tz?: string;
  relativeRange?: number;
  format?: string;
}) {
  const date = new Date();
  const timeZoneOffset = date.getTimezoneOffset();
  const sign = timeZoneOffset > 0 ? '-' : '+';
  const hoursOffset = Math.abs(timeZoneOffset) / 60;
  const isLocalUtc = timeZoneOffset === 0;

  const isUtc = useUtcStore((state) => state.isUtc);
  const setIsUtc = useUtcStore((state) => state.setIsUtc);

  useEffect(() => {
    setIsUtc(isLocalUtc);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isLocalUtc]);

  if (!value) {
    return { innerContent: '-', popContent: '-', isUtc, setIsUtc, sign, hoursOffset };
  }

  const normalizedValue = normalizeTimestamp(value);
  const localeOption = locale === 'zh' ? 'zh-cn' : 'en';
  let datetime = dayjs(normalizedValue);

  if (type === 'utc') {
    datetime = datetime.utc();
  }

  if (tz) {
    datetime = datetime.tz(tz);
  }

  datetime = datetime.locale(localeOption);

  const absoluteString = formatToDatetime(normalizedValue, { locale: localeOption, tz, format });

  let relativeString;

  if (from) {
    relativeString = datetime.from(from, withoutSuffix);
  } else if (to) {
    relativeString = datetime.to(to, withoutSuffix);
  } else if (relativeRange) {
    const diffTime = datetime.diff(dayjs());
    if (Math.abs(diffTime) > relativeRange) {
      relativeString = absoluteString;
    }
  }

  if (!relativeString) {
    relativeString = datetime.fromNow(withoutSuffix);
  }

  let innerContent = relativeString;
  let popContent = absoluteString;

  if (type === 'absolute') {
    innerContent = absoluteString;
    popContent = relativeString;
  }

  if (type === 'utc') {
    if (isUtc) {
      innerContent = formatToDatetime(normalizedValue, { locale: localeOption, tz, isUtc: true, format });
      popContent = formatToDatetime(normalizedValue, { locale: localeOption, tz, isUtc: true, format });
    } else {
      innerContent = absoluteString;
      popContent = relativeString;
    }
  }

  return { innerContent, popContent, isUtc, setIsUtc, sign, hoursOffset, relativeString, absoluteString };
}

function UTCChip({
  locale,
  isUtc = false,
  setIsUtc,
  useShortTimezone = true,
}: {
  locale: Locale;
  isUtc?: boolean;
  setIsUtc: (data: boolean) => void;
  useShortTimezone?: boolean;
}) {
  const text = useMemo(() => {
    const UTC = useShortTimezone ? 'shortUTC' : 'utc';
    const LOCAL = useShortTimezone ? 'shortLocal' : 'local';
    // fallback to en
    const config = translations[locale] || translations.en;

    if (isUtc) {
      return `${config[UTC]}`;
    }

    return `${config[LOCAL]}`;
  }, [locale, useShortTimezone, isUtc]);

  return (
    <Box
      component="span"
      sx={{
        color: 'inherit',
        cursor: 'pointer',
        border: '1px solid',
        borderColor: 'divider',
        borderRadius: '20px',
        padding: '4px 8px',
        lineHeight: 1,
      }}
      onClick={() => setIsUtc(!isUtc)}>
      {text}
    </Box>
  );
}

export default function RelativeTime({
  value,
  locale = 'en',
  withoutSuffix = false,
  from = '',
  to = '',
  type = 'relative',
  tz = undefined,
  relativeRange = undefined,
  enableTooltip = true,
  useShortTimezone = false,
  disableTimezone = false,
  placement = 'top-end',
  format = 'lll',
  mode = 'all',
  ...rest
}: RelativeTimeProps) {
  const { innerContent, popContent, isUtc, setIsUtc, relativeString } = useRelativeTime({
    value,
    locale,
    withoutSuffix,
    from,
    to,
    type: type === 'all' ? 'utc' : type,
    tz,
    relativeRange,
    format,
  });

  const allContent = (
    <Box
      {...rest}
      sx={[
        {
          display: 'inline-flex',
          alignItems: 'center',
          gap: 0.5,
        },
        ...(Array.isArray(rest.sx) ? rest.sx : [rest.sx]),
      ]}>
      <Box component="span" {...rest} sx={{}}>
        {innerContent}
      </Box>

      <Box component="span" sx={{ color: 'inherit' }}>
        ·
      </Box>

      <Box component="span" sx={{ color: 'inherit' }}>
        {relativeString}
      </Box>

      {!disableTimezone && (
        <>
          <Box component="span" sx={{ color: 'inherit' }}>
            ·
          </Box>

          <UTCChip locale={locale} isUtc={isUtc} setIsUtc={setIsUtc} useShortTimezone={useShortTimezone} />
        </>
      )}
    </Box>
  );

  // 优先通过 mode 来决定显示什么内容
  if (mode === 'daysLeft') {
    return (
      <Tooltip title={allContent} placement={placement} enterTouchDelay={0}>
        <Box component="span">{relativeString}</Box>
      </Tooltip>
    );
  }

  if (type === 'all' && mode === 'all') {
    return (
      <Tooltip title={undefined} placement={placement} enterTouchDelay={0}>
        {allContent}
      </Tooltip>
    );
  }

  return (
    <Tooltip title={enableTooltip ? popContent : undefined} placement={placement} enterTouchDelay={0}>
      <Box
        sx={{
          display: 'inline-flex',
          alignItems: 'center',
          gap: 1,
        }}>
        <Box component="span" {...rest}>
          {innerContent}
        </Box>

        {type === 'utc' && !disableTimezone && (
          <UTCChip locale={locale} isUtc={isUtc} setIsUtc={setIsUtc} useShortTimezone={useShortTimezone} />
        )}
      </Box>
    </Tooltip>
  );
}
