import type { FC } from '../../../lib/teact/teact';
import React, {
  memo, useCallback, useMemo, useState,
} from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';

import type { ApiChat, ApiExportedInvite } from '../../../api/types';
import { ManagementScreens } from '../../../types';

import { STICKER_SIZE_INVITES, TME_LINK_PREFIX } from '../../../config';
import { getMainUsername, isChatChannel } from '../../../global/helpers';
import { selectChat, selectTabState } from '../../../global/selectors';
import { copyTextToClipboard } from '../../../util/clipboard';
import { formatCountdown, MILLISECONDS_IN_DAY } from '../../../util/dates/dateFormat';
import { getServerTime } from '../../../util/serverTime';
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';

import useInterval from '../../../hooks/schedulers/useInterval';
import useFlag from '../../../hooks/useFlag';
import useForceUpdate from '../../../hooks/useForceUpdate';
import useHistoryBack from '../../../hooks/useHistoryBack';
import useLang from '../../../hooks/useLang';
import useOldLang from '../../../hooks/useOldLang';

import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview';
import Icon from '../../common/icons/Icon';
import LinkField from '../../common/LinkField';
import NothingFound from '../../common/NothingFound';
import ConfirmDialog from '../../ui/ConfirmDialog';
import ListItem, { type MenuItemContextAction } from '../../ui/ListItem';

type OwnProps = {
  chatId: string;
  onClose: NoneToVoidFunction;
  onScreenSelect: (screen: ManagementScreens) => void;
  isActive: boolean;
};

type StateProps = {
  chat?: ApiChat;
  isChannel?: boolean;
  exportedInvites?: ApiExportedInvite[];
  revokedExportedInvites?: ApiExportedInvite[];
};

const BULLET = '\u2022';

function inviteComparator(i1: ApiExportedInvite, i2: ApiExportedInvite) {
  const { isPermanent: i1IsPermanent, usage: i1Usage = 0, date: i1Date } = i1;
  const { isPermanent: i2IsPermanent, usage: i2Usage = 0, date: i2Date } = i2;
  if (i1IsPermanent || i2IsPermanent) return Number(i1IsPermanent) - Number(i2IsPermanent);
  if (i1Usage || i2Usage) return i2Usage - i1Usage;
  return i2Date - i1Date;
}

const ManageInvites: FC<OwnProps & StateProps> = ({
  chatId,
  chat,
  exportedInvites,
  revokedExportedInvites,
  isActive,
  isChannel,
  onClose,
  onScreenSelect,
}) => {
  const {
    setEditingExportedInvite,
    showNotification,
    editExportedChatInvite,
    deleteExportedChatInvite,
    deleteRevokedExportedChatInvites,
    setOpenedInviteInfo,
  } = getActions();

  const lang = useLang();
  const oldLang = useOldLang();

  const [isDeleteRevokeAllDialogOpen, openDeleteRevokeAllDialog, closeDeleteRevokeAllDialog] = useFlag();
  const [isRevokeDialogOpen, openRevokeDialog, closeRevokeDialog] = useFlag();
  const [revokingInvite, setRevokingInvite] = useState<ApiExportedInvite | undefined>();
  const [isDeleteDialogOpen, openDeleteDialog, closeDeleteDialog] = useFlag();
  const [deletingInvite, setDeletingInvite] = useState<ApiExportedInvite | undefined>();

  useHistoryBack({
    isActive,
    onBack: onClose,
  });

  const hasDetailedCountdown = useMemo(() => {
    if (!exportedInvites) return undefined;
    return exportedInvites
      .some(({ expireDate }) => (
        expireDate && (expireDate - getServerTime() < MILLISECONDS_IN_DAY / 1000)
      ));
  }, [exportedInvites]);
  const forceUpdate = useForceUpdate();
  useInterval(forceUpdate, hasDetailedCountdown ? 1000 : undefined);

  const chatMainUsername = useMemo(() => chat && getMainUsername(chat), [chat]);
  const primaryInvite = exportedInvites?.find(({ isPermanent }) => isPermanent);
  const primaryInviteLink = chatMainUsername ? `${TME_LINK_PREFIX}${chatMainUsername}` : primaryInvite?.link;
  const temporalInvites = useMemo(() => {
    const invites = chat?.usernames ? exportedInvites : exportedInvites?.filter(({ isPermanent }) => !isPermanent);
    return invites?.sort(inviteComparator);
  }, [chat?.usernames, exportedInvites]);

  const editInvite = (invite: ApiExportedInvite) => {
    setEditingExportedInvite({ chatId, invite });
    onScreenSelect(ManagementScreens.EditInvite);
  };

  const revokeInvite = useCallback((invite: ApiExportedInvite) => {
    const {
      link, title, isRequestNeeded, expireDate, usageLimit,
    } = invite;
    editExportedChatInvite({
      chatId,
      link,
      title,
      isRequestNeeded,
      expireDate,
      usageLimit,
      isRevoked: true,
    });
  }, [chatId, editExportedChatInvite]);

  const askToRevoke = useCallback((invite: ApiExportedInvite) => {
    setRevokingInvite(invite);
    openRevokeDialog();
  }, [openRevokeDialog]);

  const handleRevoke = useCallback(() => {
    if (!revokingInvite) return;
    revokeInvite(revokingInvite);
    setRevokingInvite(undefined);
    closeRevokeDialog();
  }, [closeRevokeDialog, revokeInvite, revokingInvite]);

  const handleCreateNewClick = useCallback(() => {
    onScreenSelect(ManagementScreens.EditInvite);
  }, [onScreenSelect]);

  const handlePrimaryRevoke = useCallback(() => {
    if (primaryInvite) {
      askToRevoke(primaryInvite);
    }
  }, [askToRevoke, primaryInvite]);

  const handleDeleteAllRevoked = useCallback(() => {
    deleteRevokedExportedChatInvites({ chatId });
    closeDeleteRevokeAllDialog();
  }, [chatId, closeDeleteRevokeAllDialog, deleteRevokedExportedChatInvites]);

  const showInviteInfo = useCallback((invite: ApiExportedInvite) => {
    setOpenedInviteInfo({ chatId, invite });
    onScreenSelect(ManagementScreens.InviteInfo);
  }, [chatId, onScreenSelect, setOpenedInviteInfo]);

  const deleteInvite = useCallback((invite: ApiExportedInvite) => {
    deleteExportedChatInvite({ chatId, link: invite.link });
  }, [chatId, deleteExportedChatInvite]);

  const askToDelete = useCallback((invite: ApiExportedInvite) => {
    setDeletingInvite(invite);
    openDeleteDialog();
  }, [openDeleteDialog]);

  const handleDelete = useCallback(() => {
    if (!deletingInvite) return;
    deleteInvite(deletingInvite);
    setDeletingInvite(undefined);
    closeDeleteDialog();
  }, [closeDeleteDialog, deleteInvite, deletingInvite]);

  const copyLink = useCallback((link: string) => {
    copyTextToClipboard(link);
    showNotification({
      message: oldLang('LinkCopied'),
    });
  }, [oldLang, showNotification]);

  const prepareUsageText = (invite: ApiExportedInvite) => {
    const {
      usage = 0, usageLimit, expireDate, isPermanent, requested, isRevoked,
    } = invite;
    let text = '';
    if (!isRevoked && usageLimit && usage < usageLimit) {
      text = oldLang('CanJoin', usageLimit - usage);
    } else if (usage) {
      text = oldLang('PeopleJoined', usage);
    } else {
      text = oldLang('NoOneJoined');
    }

    if (isRevoked) {
      text += ` ${BULLET} ${oldLang('Revoked')}`;
      return text;
    }

    if (requested) {
      text += ` ${BULLET} ${oldLang('JoinRequests', requested)}`;
    }

    if (usageLimit !== undefined && usage === usageLimit) {
      text += ` ${BULLET} ${oldLang('LinkLimitReached')}`;
    } else if (expireDate) {
      const diff = expireDate - getServerTime();
      text += ` ${BULLET} `;
      if (diff > 0) {
        text += oldLang('InviteLink.ExpiresIn', formatCountdown(lang, diff));
      } else {
        text += oldLang('InviteLink.Expired');
      }
    } else if (isPermanent) {
      text += ` ${BULLET} ${oldLang('Permanent')}`;
    }

    return text;
  };

  const getInviteIconClass = (invite: ApiExportedInvite) => {
    const {
      usage = 0, usageLimit, isRevoked, expireDate,
    } = invite;
    if (isRevoked) {
      return 'link-status-icon-gray';
    }
    if (usageLimit && usage < usageLimit) {
      return 'link-status-icon-green';
    }
    if (expireDate) {
      const diff = (expireDate - getServerTime()) * 1000;
      if (diff <= 0) {
        return 'link-status-icon-red';
      }
    }
    return 'link-status-icon-blue';
  };

  const prepareContextActions = (invite: ApiExportedInvite) => {
    const actions: MenuItemContextAction[] = [];
    actions.push({
      title: oldLang('Copy'),
      icon: 'copy',
      handler: () => copyLink(invite.link),
    });

    if (!invite.isPermanent && !invite.isRevoked) {
      actions.push({
        title: oldLang('Edit'),
        icon: 'edit',
        handler: () => editInvite(invite),
      });
    }

    if (!invite.isRevoked) {
      actions.push({
        title: oldLang('RevokeButton'),
        icon: 'delete',
        handler: () => askToRevoke(invite),
        destructive: true,
      });
    } else {
      actions.push({
        title: oldLang('DeleteLink'),
        icon: 'delete',
        handler: () => askToDelete(invite),
        destructive: true,
      });
    }
    return actions;
  };

  return (
    <div className="Management ManageInvites">
      <div className="panel-content custom-scroll">
        <div className="section">
          <AnimatedIconWithPreview
            tgsUrl={LOCAL_TGS_URLS.Invite}
            size={STICKER_SIZE_INVITES}
            className="section-icon"
          />
          <p className="section-help">{isChannel ? oldLang('PrimaryLinkHelpChannel') : oldLang('PrimaryLinkHelp')}</p>
        </div>
        {primaryInviteLink && (
          <div className="section">
            <LinkField
              className="settings-input"
              link={primaryInviteLink}
              withShare
              onRevoke={!chat?.usernames ? handlePrimaryRevoke : undefined}
              title={chat?.usernames ? oldLang('PublicLink') : oldLang('lng_create_permanent_link_title')}
            />
          </div>
        )}
        <div className="section" teactFastList>
          <ListItem icon="add" withPrimaryColor key="create" className="create-item" onClick={handleCreateNewClick}>
            {oldLang('CreateNewLink')}
          </ListItem>
          {(!temporalInvites || !temporalInvites.length) && <NothingFound text="No links found" key="nothing" />}
          {temporalInvites?.map((invite) => (
            <ListItem
              leftElement={<Icon name="link" className={`link-status-icon ${getInviteIconClass(invite)}`} />}
              secondaryIcon="more"
              multiline

              onClick={() => showInviteInfo(invite)}
              contextActions={prepareContextActions(invite)}
              key={invite.link}
            >
              <span className="title invite-title">{invite.title || invite.link}</span>
              <span className="subtitle" dir="auto">
                {prepareUsageText(invite)}
              </span>
            </ListItem>
          ))}
          <p className="section-help hint" key="links-hint">{oldLang('ManageLinksInfoHelp')}</p>
        </div>
        {revokedExportedInvites && Boolean(revokedExportedInvites.length) && (
          <div className="section" teactFastList>
            <p className="section-help" key="title">{oldLang('RevokedLinks')}</p>
            <ListItem
              icon="delete"
              destructive
              key="delete"
              onClick={openDeleteRevokeAllDialog}
            >
              <span className="title">{oldLang('DeleteAllRevokedLinks')}</span>
            </ListItem>
            {revokedExportedInvites?.map((invite) => (
              <ListItem
                leftElement={<Icon name="link" className={`link-status-icon ${getInviteIconClass(invite)}`} />}
                secondaryIcon="more"
                multiline

                onClick={() => showInviteInfo(invite)}
                contextActions={prepareContextActions(invite)}
                key={invite.link}
              >
                <span className="title">{invite.title || invite.link}</span>
                <span className="subtitle" dir="auto">
                  {prepareUsageText(invite)}
                </span>
              </ListItem>
            ))}
          </div>
        )}
      </div>
      <ConfirmDialog
        isOpen={isDeleteRevokeAllDialogOpen}
        onClose={closeDeleteRevokeAllDialog}
        title={oldLang('DeleteAllRevokedLinks')}
        text={oldLang('DeleteAllRevokedLinkHelp')}
        confirmIsDestructive
        confirmLabel={oldLang('DeleteAll')}
        confirmHandler={handleDeleteAllRevoked}
      />
      <ConfirmDialog
        isOpen={isRevokeDialogOpen}
        onClose={closeRevokeDialog}
        title={oldLang('RevokeLink')}
        text={oldLang('RevokeAlert')}
        confirmIsDestructive
        confirmLabel={oldLang('RevokeButton')}
        confirmHandler={handleRevoke}
      />
      <ConfirmDialog
        isOpen={isDeleteDialogOpen}
        onClose={closeDeleteDialog}
        title={oldLang('DeleteLink')}
        text={oldLang('DeleteLinkHelp')}
        confirmIsDestructive
        confirmLabel={oldLang('Delete')}
        confirmHandler={handleDelete}
      />
    </div>
  );
};

export default memo(withGlobal<OwnProps>(
  (global, { chatId }): StateProps => {
    const { invites, revokedInvites } = selectTabState(global).management.byChatId[chatId] || {};
    const chat = selectChat(global, chatId);
    const isChannel = chat && isChatChannel(chat);

    return {
      exportedInvites: invites,
      revokedExportedInvites: revokedInvites,
      chat,
      isChannel,
    };
  },
)(ManageInvites));
