import { type GroupPost } from 'src/types/groups';
import {
  type Post,
  type ShareGroupPostIdMetadataInput,
  type ShareMetadata,
  type ShareMetadataInput,
  type SharePostIdMetadataInput,
} from 'src/types/posts';

type OriginalReference =
  | { type: 'feed'; id: number }
  | { type: 'group'; id: number; groupId: number };

const isShare = (
  metadata: ShareMetadata | null | undefined,
): metadata is ShareMetadata =>
  !!metadata &&
  ('SHARE_POST_ID' in metadata || 'SHARE_GROUP_POST_ID' in metadata);

const isFeedShare = (
  metadata: ShareMetadata,
): metadata is Extract<ShareMetadata, { SHARE_POST_ID: unknown }> =>
  'SHARE_POST_ID' in metadata;

const isGroupShare = (
  metadata: ShareMetadata,
): metadata is Extract<ShareMetadata, { SHARE_GROUP_POST_ID: unknown }> =>
  'SHARE_GROUP_POST_ID' in metadata;

const getOriginal = (metadata: ShareMetadata): OriginalReference => {
  if (isFeedShare(metadata)) {
    return { type: 'feed', id: metadata.SHARE_POST_ID.id };
  }
  return {
    type: 'group',
    id: metadata.SHARE_GROUP_POST_ID.id,
    groupId: metadata.SHARE_GROUP_POST_ID.groupId,
  };
};

const getLink = (metadata: ShareMetadata): string =>
  isFeedShare(metadata)
    ? metadata.SHARE_POST_ID.link
    : metadata.SHARE_GROUP_POST_ID.link;

const fromFeedPostId = (id: number): SharePostIdMetadataInput => ({
  SHARE_POST_ID: { id },
});

const fromGroupPostId = (
  id: number,
  groupId: number,
): ShareGroupPostIdMetadataInput => ({
  SHARE_GROUP_POST_ID: { id, groupId },
});

const toCreatePayload = (metadata: ShareMetadata): ShareMetadataInput => {
  const original = getOriginal(metadata);
  return original.type === 'feed'
    ? fromFeedPostId(original.id)
    : fromGroupPostId(original.id, original.groupId);
};

/**
 * Maps a post to the shape expected by usePostsViewTracking. Extracts the
 * original-post reference from share metadata so the hook can mark both the
 * container and the original as viewed in one pass.
 */
const toViewTrackingPost = (post: Post | GroupPost) => {
  const groupId = 'groupId' in post ? post.groupId : post.group?.id;
  const original = isShare(post.metadata) ? getOriginal(post.metadata) : null;
  return {
    id: post.id,
    groupId,
    original: original
      ? {
          id: original.id,
          ...(original.type === 'group' && { groupId: original.groupId }),
        }
      : undefined,
  };
};

/**
 * Builds the metadata input that should be sent to the backend when sharing
 * `post`. Always references `post` directly so that sharing a reshared post
 * embeds that reshare (with its own text) rather than the underlying original.
 */
const fromSourcePost = (post: Post | GroupPost): ShareMetadataInput => {
  if ('groupId' in post && typeof post.groupId === 'number') {
    return fromGroupPostId(post.id, post.groupId);
  }

  const feedGroup = (post as Post).group;
  if (feedGroup?.id) return fromGroupPostId(post.id, feedGroup.id);

  return fromFeedPostId(post.id);
};

export type { OriginalReference };

export const withShareMetadata = {
  isShare,
  isFeedShare,
  isGroupShare,
  getOriginal,
  getLink,
  fromFeedPostId,
  fromGroupPostId,
  fromSourcePost,
  toCreatePayload,
  toViewTrackingPost,
};
