/* eslint-disable react/prop-types */
import React, { MouseEvent } from 'react';
import { useCreation, useMemoizedFn } from 'ahooks';
import { useTheme, Link } from '@mui/material';
import { WELLKNOWN_SERVICE_PATH_PREFIX } from '@abtnode/constant';
import { joinURL, withQuery } from 'ufo';
import isEmpty from 'lodash/isEmpty';
import { getActivityLink } from '../utils';

/**
 * Activity types enum for type safety
 * @readonly
 * @enum {string}
 */
const ACTIVITY_TYPES = {
  COMMENT: 'comment',
  LIKE: 'like',
  FOLLOW: 'follow',
  TIPS: 'tips',
  MENTION: 'mention',
  ASSIGN: 'assign',
} as const;

type ActivityTypeValues = (typeof ACTIVITY_TYPES)[keyof typeof ACTIVITY_TYPES];

/**
 * Activity descriptions mapping
 * @type {Object.<string, React.ReactNode>}
 */
const ACTIVITY_DESCRIPTIONS: Record<ActivityTypeValues, (targetType: string, count?: number) => React.ReactNode> = {
  comment: (targetType: string, count?: number) =>
    count && count > 1 ? (
      <>
        left {count} comments on your {targetType}
      </>
    ) : (
      <>commented on your {targetType}</>
    ),
  like: (targetType: string) => <>liked your {targetType}</>,
  follow: () => <>followed you</>,
  tips: (targetType: string) => <>gave tips to your {targetType}</>,
  mention: (targetType: string) => <>mentioned you in {targetType}</>,
  assign: () => <>assigned you a task</>,
};

interface UserData {
  did: string;
  fullName: string;
}

interface UserLinkProps {
  user: UserData;
  color?: string;
}

interface CustomMouseEvent extends MouseEvent<HTMLAnchorElement> {
  customPreventRedirect?: boolean;
}

/**
 * UserLink component for rendering a user's name as a profile link
 * Memoized to prevent unnecessary re-renders
 */
function UserLink({ user, color = undefined }: UserLinkProps) {
  const { palette } = useTheme();
  const profileLink = withQuery(joinURL(WELLKNOWN_SERVICE_PATH_PREFIX, 'user'), { did: user.did });
  // eslint-disable-next-line @typescript-eslint/naming-convention
  const _color = color || palette.text.primary;

  return (
    <Link
      href={profileLink}
      color={_color}
      target="_blank"
      onClick={(e: CustomMouseEvent) => {
        e.customPreventRedirect = true;
      }}
      sx={{
        fontWeight: 600,
        textDecoration: 'none',
        '&:hover': { cursor: 'pointer' },
      }}>
      {user.fullName || 'System'}
    </Link>
  );
}

UserLink.displayName = 'UserLink';

interface ActivityTarget {
  type: string;
  name: string;
}

interface Activity {
  type: ActivityTypeValues;
  target: ActivityTarget;
}

interface ExtraParams {
  linkColor?: string;
  [key: string]: any;
}

interface ActivityTitleProps {
  activity: Activity;
  users: UserData[];
  actors: string[];
  extra?: ExtraParams;
  mountPoint?: string;
}

/**
 * A hook that returns a formatted activity title with linked usernames
 * @param {Object} params - The parameters object
 * @param {keyof typeof ACTIVITY_TYPES} params.type - The activity type
 * @param {Object} params.target - The target object
 * @param {Array<{did: string, fullName: string}>} params.users - Array of user objects
 * @param {Object} params.extra - Extra parameters
 * @returns {React.ReactNode} Formatted title with linked usernames
 */
export default function useActivityTitle({ activity, users, actors, extra = {}, mountPoint = '' }: ActivityTitleProps) {
  const { palette } = useTheme();
  const { type, target } = activity || {};
  const { type: targetType } = target || {};
  const { linkColor = palette.text.primary } = extra || {};

  // Create a map of users by their DID for efficient lookup
  const usersMap = useCreation(() => {
    if (!Array.isArray(users)) return new Map<string, UserData>();
    const map = new Map<string, UserData>();
    users.forEach((user) => {
      if (user?.did && !map.has(user.did)) {
        map.set(user.did, user);
      }
    });
    return map;
  }, [users]);

  // Get unique users from actors, using the map and providing fallback for missing users
  const uniqueUsers = useCreation(() => {
    if (!Array.isArray(actors)) return [];

    return actors
      .map((actorId) => {
        if (!actorId) return null;
        // If user exists in map, return the user object, otherwise create a basic object with DID
        return usersMap.get(actorId) || { did: actorId, fullName: 'System' };
      })
      .filter(Boolean) as UserData[];
  }, [actors, usersMap]);

  // Memoized function to format user names with links
  const formatLinkedUserNames = useMemoizedFn(() => {
    if (!Array.isArray(uniqueUsers) || uniqueUsers.length === 0) {
      return null;
    }

    // Early return for single user case
    if (uniqueUsers.length === 1) {
      return <UserLink user={uniqueUsers[0]} color={linkColor} />;
    }

    // Get all users except the last one for multi-user cases
    const initialUsers = uniqueUsers.slice(0, -1);
    const lastUser = uniqueUsers[uniqueUsers.length - 1];

    // Early return for two users case
    if (uniqueUsers.length === 2) {
      return (
        <>
          <UserLink user={initialUsers[0]} color={linkColor} />
          {' and '}
          <UserLink user={lastUser} color={linkColor} />
        </>
      );
    }

    // Handle three or more users
    const isMoreThanThree = uniqueUsers.length > 3;
    const displayUsers = isMoreThanThree ? uniqueUsers.slice(0, 2) : initialUsers;

    return (
      <>
        {displayUsers.map((user, index) => (
          <React.Fragment key={user.did}>
            <UserLink user={user} color={linkColor} />
            {index < displayUsers.length - 1 ? ', ' : ''}
          </React.Fragment>
        ))}
        {isMoreThanThree ? (
          `, and ${uniqueUsers.length - 2} others`
        ) : (
          <>
            , and <UserLink user={lastUser} color={linkColor} />
          </>
        )}
      </>
    );
  });

  // Memoized function to get activity description
  const getActivityDescription = useMemoizedFn(() => {
    const descriptionFn = type ? ACTIVITY_DESCRIPTIONS[type] : null;
    return descriptionFn ? descriptionFn(targetType, users.length) : null;
  });

  // Create the final title using memoization
  const title = useCreation(() => {
    const linkedNames = formatLinkedUserNames();
    const description = getActivityDescription();

    if (!linkedNames || !description) {
      return null;
    }

    return (
      <>
        {linkedNames} {description}
      </>
    );
  }, [type, targetType, uniqueUsers, formatLinkedUserNames, getActivityDescription]);

  const targetLink = useCreation(() => {
    if (!activity) return null;
    const link = getActivityLink(activity);
    if (link?.targetLink) {
      return joinURL(mountPoint, link.targetLink);
    }
    return null;
  }, [activity, mountPoint]);

  if (!type || isEmpty(target)) {
    return null;
  }

  return (
    <>
      {title}{' '}
      {targetLink && (
        <Link
          href={targetLink}
          color={linkColor}
          target="_blank"
          sx={{ textDecoration: 'none' }}
          onClick={(e: CustomMouseEvent) => {
            e.customPreventRedirect = true;
          }}>
          {target.name}
        </Link>
      )}
    </>
  );
}
