import { AmityCommunityMemberStatusFilter } from '~/communityRepository/constants';

export const CommunityPostSettings = Object.freeze({
  ONLY_ADMIN_CAN_POST: 'ONLY_ADMIN_CAN_POST',
  ADMIN_REVIEW_POST_REQUIRED: 'ADMIN_REVIEW_POST_REQUIRED',
  ANYONE_CAN_POST: 'ANYONE_CAN_POST',
});

export const CommunityPostSettingMaps = Object.freeze({
  ONLY_ADMIN_CAN_POST: {
    needApprovalOnPostCreation: false,
    onlyAdminCanPost: true,
  },
  ADMIN_REVIEW_POST_REQUIRED: {
    needApprovalOnPostCreation: true,
    onlyAdminCanPost: false,
  },
  ANYONE_CAN_POST: {
    needApprovalOnPostCreation: false,
    onlyAdminCanPost: false,
  },
});

export const DefaultCommunityPostSetting = 'ONLY_ADMIN_CAN_POST';

declare global {
  namespace Amity {
    const enum CommunitySortByEnum {
      FirstCreated = 'firstCreated',
      LastCreated = 'lastCreated',
    }

    type CommunitySortBy = `${Amity.CommunitySortByEnum}`;

    const enum SearchCommunitySortByEnum {
      FirstCreated = 'firstCreated',
      LastCreated = 'lastCreated',
      DisplayName = 'displayName',
    }

    type SearchCommunitySortBy = `${Amity.SearchCommunitySortByEnum}`;

    const enum CommunityMemberSortByEnum {
      FirstCreated = 'firstCreated',
      LastCreated = 'lastCreated',
    }

    type CommunityMemberSortBy = `${Amity.CommunityMemberSortByEnum}`;

    const enum SearchCommunityMemberSortByEnum {
      FirstCreated = 'firstCreated',
      LastCreated = 'lastCreated',
      DisplayName = 'displayName',
    }

    type SearchCommunityMemberSortBy = `${Amity.SearchCommunityMemberSortByEnum}`;

    type CommunityActionType =
      | 'onCreate'
      | 'onUpdate'
      | 'onDelete'
      | 'onJoin'
      | 'onLeft'
      | 'onMemberCountChanged';

    type CommunityMemberActionType =
      | 'onJoin'
      | 'onLeft'
      | 'onBan'
      | 'onUnban'
      | 'onMemberCountChanged';

    type RawCommunity = {
      communityId: string;

      displayName: string;
      avatarFileId?: File<'image'>['fileId'];
      description?: string;

      channelId: Amity.Channel['channelId'];
      userId: Amity.InternalUser['userId'];

      isOfficial?: boolean;
      isPublic?: boolean;
      isJoined?: boolean;
      onlyAdminCanPost?: boolean;
      needApprovalOnPostCreation?: boolean;

      postsCount: number;
      membersCount: number;

      categoryIds: Amity.InternalCategory['categoryId'][];

      hasFlaggedComment: boolean;
      hasFlaggedPost: boolean;

      allowCommentInStory?: boolean;

      isDiscoverable?: boolean;
      requiresJoinApproval?: boolean;
    } & Amity.Taggable &
      Amity.Metadata &
      Amity.Timestamps &
      Amity.SoftDelete &
      Amity.Subscribable;

    type InternalCommunity = Omit<
      Amity.RawCommunity,
      'onlyAdminCanPost' | 'needApprovalOnPostCreation'
    > &
      Amity.CommunityStorySettings & {
        postSetting?: ValueOf<typeof CommunityPostSettings>;
      };

    type Community = Amity.InternalCommunity & Amity.CommunityLinkedObject;

    type QueryCommunities = {
      membership?: 'all' | 'member' | 'notMember';
      categoryId?: Amity.InternalCategory['categoryId'];
      includeDeleted?: boolean;
      tags?: Amity.Taggable['tags'];
      sortBy?: Amity.CommunitySortBy | Amity.CommunitySortByEnum;
      page?: string;
      limit?: number;
      includeDiscoverablePrivateCommunity?: boolean;
    };

    type QueryJoinCommunity = {
      communityId: string;
      status: Amity.JoinRequestStatus;
      sortBy?: Amity.CommunitySortBy | Amity.CommunitySortByEnum;
      options?: {
        limit?: number;
        token?: string;
      };
    };

    type SearchQueryCommunities = {
      displayName?: string;
      membership?: 'all' | 'member' | 'notMember';
      categoryId?: Amity.InternalCategory['categoryId'];
      includeDeleted?: boolean;
      tags?: Amity.Taggable['tags'];
      sortBy?: Amity.SearchCommunitySortBy | Amity.SearchCommunitySortByEnum;
      page?: string;
      limit?: number;
      includeDiscoverablePrivateCommunity?: boolean;
    };

    type QueryJoinRequest = {
      communityId: string;
      status: Amity.JoinRequestStatus;
      targetType: 'community';
      type: Amity.JoinRequestType;
      sortBy?: Amity.CommunitySortBy | Amity.CommunitySortByEnum;
      options?: {
        limit?: number;
        token?: string;
      };
      page?: string;
    };

    type QueryJoinRequestList = {
      communityIds: string[];
      sortBy?: Amity.CommunitySortBy | Amity.CommunitySortByEnum;
      options?: {
        limit?: number;
        token?: string;
      };
      page?: string;
    };

    type CommunityLiveCollection = Amity.LiveCollectionParams<Omit<QueryCommunities, 'page'>>;

    type RecommendedCommunityLiveCollection = Amity.LiveCollectionParams<{
      limit?: number;
      includeDiscoverablePrivateCommunity?: boolean;
    }>;
    type TrendingCommunityLiveCollection = Amity.LiveCollectionParams<{
      limit?: number;
      includeDiscoverablePrivateCommunity?: boolean;
    }>;

    type JoinRequestLiveCollection = Amity.LiveCollectionParams<QueryJoinRequest>;

    type JoinRequestListLiveCollection = Amity.LiveCollectionParams<QueryJoinRequestList>;

    type SearchCommunityLiveCollection = Amity.LiveCollectionParams<
      Omit<SearchQueryCommunities, 'page'>
    >;

    type CommunityLiveCollectionCache = Amity.LiveCollectionCache<
      Amity.Community['communityId'],
      Pick<QueryCommunities, 'page'>
    >;

    type RecommendedCommunityLiveCollectionCache = Amity.CommunityLiveCollectionCache;
    type TrendingCommunityLiveCollectionCache = Amity.CommunityLiveCollectionCache;

    type SearchCommunityLiveCollectionCache = Amity.LiveCollectionCache<
      Amity.Community['communityId'],
      Pick<SearchQueryCommunities, 'page'>
    >;

    type JoinRequestLiveCollectionCache = Amity.LiveCollectionCache<
      Amity.JoinRequest['joinRequestId'],
      Pick<QueryJoinRequest, 'page'>
    >;

    type JoinRequestListLiveCollectionCache = Amity.LiveCollectionCache<
      Amity.JoinRequest['joinRequestId'],
      Pick<QueryJoinRequestList, 'page'>
    >;

    type QueryCommunityMembers = {
      communityId: string;
      memberships?: ('banned' | 'member')[];
      roles?: string[];
      sortBy?: Amity.CommunityMemberSortByEnum | Amity.CommunityMemberSortBy;
      page?: string;
      limit?: number;
      includeDeleted?: boolean;
    };

    type QuerySearchCommunityMembers = {
      communityId: string;
      memberships?: ('banned' | 'member')[];
      roles?: string[];
      sortBy?: Amity.SearchCommunityMemberSortByEnum | Amity.SearchCommunityMemberSortBy;
      search?: Amity.InternalUser['displayName'] | Amity.InternalUser['userId'];
      page?: string;
      limit?: number;
      includeDeleted?: boolean;
    };

    type CommunityMemberLiveCollection = Amity.LiveCollectionParams<
      Omit<QueryCommunityMembers, 'page'>
    >;

    type SearchCommunityMemberLiveCollection = Amity.LiveCollectionParams<
      Omit<QuerySearchCommunityMembers, 'page'>
    >;

    type CommunityMemberLiveCollectionCache = Amity.LiveCollectionCache<
      Amity.Membership<'community'>['userId'],
      Pick<QueryCommunityMembers, 'page'>
    >;

    type SearchCommunityMemberLiveCollectionCache = Amity.LiveCollectionCache<
      Amity.Community['communityId'],
      Pick<QuerySearchCommunityMembers, 'page'>
    >;

    type QuerySemanticSearchCommunity = {
      query: string;
      categoryIds?: string[];
      filter?: AmityCommunityMemberStatusFilter;
      options?: {
        limit?: number;
        token?: string;
      };
      tags?: string[];
      includeDiscoverablePrivateCommunity?: boolean;
    };

    type SemanticSearchCommunityLiveCollection = Amity.LiveCollectionParams<
      Omit<QuerySemanticSearchCommunity, 'page' | 'filter' | 'options'>
    > & {
      communityMembershipStatus?: AmityCommunityMemberStatusFilter;
    };

    type SemanticSearchCommunityLiveCollectionCache = Amity.LiveCollectionCache<
      Amity.Community['communityId'], // communityId:score
      QuerySemanticSearchCommunity
    >;

    type CommunityLinkedObject = {
      createInvitations: (userIds: string[]) => Promise<void>;
      getMemberInvitations: (
        params: Pick<Amity.InvitationLiveCollection, 'limit' | 'sortBy' | 'statuses'>,
        callback: Amity.LiveCollectionCallback<Amity.Invitation>,
      ) => Amity.Unsubscriber;
      getInvitation: () => Promise<Amity.Invitation | undefined>;
      join: () => Promise<Amity.JoinResult>;
      getJoinRequests: (
        params: QueryJoinRequest,
        callback: Amity.LiveCollectionCallback<Amity.JoinRequest>,
      ) => Amity.Unsubscriber;
      getMyJoinRequest: () => Promise<Amity.JoinRequest | undefined>;
    };
  }
}
