import type {
  GroupListResponse,
  GroupMemberListResponse,
  GroupMemberResponse,
  GroupResponse,
} from '../../types/dto';
import { groupService } from '@/services/message';
import { groupCacheRepository, userCacheRepository } from '@/database';
import { useGroupManagerStore } from './groupStore';
import { createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache';
import { createDedupe } from '../utils/requestDedupe';
import {
  IGroupListPagedSource,
  IGroupMemberListPagedSource,
  createRemoteGroupListSource,
  createRemoteGroupMemberListSource,
  RemoteGroupListSourceKind,
  GROUP_LIST_PAGE_SIZE,
  GROUP_MEMBER_LIST_PAGE_SIZE,
} from './sources';

const dedupe = createDedupe(() => useGroupManagerStore);

function buildMembersKey(groupId: string, page: number, pageSize: number): string {
  return `members:${groupId}:${page}:${pageSize}`;
}

function buildGroupListResponse(groups: GroupResponse[], pageSize: number): GroupListResponse {
  return {
    list: groups,
    total: groups.length,
    page: 1,
    page_size: pageSize,
    total_pages: 1,
  };
}

function buildMemberListResponse(
  members: GroupMemberResponse[],
  page: number,
  pageSize: number
): GroupMemberListResponse {
  return {
    list: members,
    total: members.length,
    page,
    page_size: pageSize,
    total_pages: 1,
  };
}

class GroupManager {
  async getGroups(
    page = 1,
    pageSize = GROUP_LIST_PAGE_SIZE,
    forceRefresh = false
  ): Promise<GroupListResponse> {
    const store = useGroupManagerStore.getState();
    const entry = store.groupsListEntry;

    if (page === 1 && !forceRefresh && entry && !isCacheExpired(entry)) {
      return buildGroupListResponse(entry.data, pageSize);
    }

    if (page === 1 && !forceRefresh && entry && isCacheExpired(entry)) {
      this.refreshGroupsInBackground(page, pageSize);
      return buildGroupListResponse(entry.data, pageSize);
    }

    if (page === 1 && !forceRefresh) {
      const localGroups = await groupCacheRepository.getAll();
      if (localGroups.length > 0) {
        const newEntry = createCacheEntry(localGroups, DEFAULT_TTL.GROUP);
        store.setGroupsListEntry(newEntry);
        this.refreshGroupsInBackground(page, pageSize);
        return buildGroupListResponse(localGroups, pageSize);
      }
    }

    return dedupe(`groups:list:${page}:${pageSize}`, async () => {
      const store = useGroupManagerStore.getState();
      const response = await groupService.getGroups(page, pageSize);
      const groups = response.list || [];
      if (page === 1) {
        store.setGroupsList(groups);
      }
      await groupCacheRepository.saveBatch(groups).catch(() => {});
      return response;
    });
  }

  private refreshGroupsInBackground(page = 1, pageSize = GROUP_LIST_PAGE_SIZE): void {
    dedupe(`groups:bg:list:${page}:${pageSize}`, async () => {
      const store = useGroupManagerStore.getState();
      const response = await groupService.getGroups(page, pageSize);
      const groups = response.list || [];
      if (page === 1) {
        store.setGroupsList(groups);
      }
      groupCacheRepository.saveBatch(groups).catch(() => {});
      return response;
    }).catch((error) => {
      console.error('[GroupManager] refreshGroupsInBackground error:', error);
    });
  }

  createGroupListSource(
    kind: RemoteGroupListSourceKind = 'cursor',
    pageSize: number = GROUP_LIST_PAGE_SIZE
  ): IGroupListPagedSource {
    return createRemoteGroupListSource(kind, pageSize);
  }

  async getGroup(groupId: string, forceRefresh = false): Promise<GroupResponse> {
    const store = useGroupManagerStore.getState();
    const entry = store.groupsMap.get(groupId);

    if (!forceRefresh && entry && !isCacheExpired(entry)) {
      return entry.data;
    }

    if (!forceRefresh && entry && isCacheExpired(entry)) {
      this.refreshGroupInBackground(groupId);
      return entry.data;
    }

    if (!forceRefresh) {
      const localGroup = await groupCacheRepository.get(groupId);
      if (localGroup) {
        store.setGroup(groupId, localGroup);
        this.refreshGroupInBackground(groupId);
        return localGroup;
      }
    }

    return dedupe(`groups:detail:${groupId}`, async () => {
      const store = useGroupManagerStore.getState();
      const group = await groupService.getGroup(groupId);
      store.setGroup(groupId, group);
      await groupCacheRepository.save(group).catch(() => {});
      return group;
    });
  }

  private refreshGroupInBackground(groupId: string): void {
    dedupe(`groups:detail:bg:${groupId}`, async () => {
      const store = useGroupManagerStore.getState();
      const group = await groupService.getGroup(groupId);
      store.setGroup(groupId, group);
      groupCacheRepository.save(group).catch(() => {});
      return group;
    }).catch((error) => {
      console.error('[GroupManager] refreshGroupInBackground error:', error);
    });
  }

  async getMembers(
    groupId: string,
    page = 1,
    pageSize = GROUP_MEMBER_LIST_PAGE_SIZE,
    forceRefresh = false
  ): Promise<GroupMemberListResponse> {
    const key = buildMembersKey(groupId, page, pageSize);
    const store = useGroupManagerStore.getState();
    const entry = store.membersMap.get(key);

    if (!forceRefresh && entry && !isCacheExpired(entry)) {
      return buildMemberListResponse(entry.data, page, pageSize);
    }

    if (!forceRefresh && entry && isCacheExpired(entry)) {
      this.refreshMembersInBackground(groupId, page, pageSize);
      return buildMemberListResponse(entry.data, page, pageSize);
    }

    if (page === 1 && !forceRefresh) {
      const localMembers = await groupCacheRepository.getMembers(groupId);
      if (localMembers.length > 0) {
        store.setMembers(groupId, localMembers, page, pageSize);
        this.refreshMembersInBackground(groupId, page, pageSize);
        return buildMemberListResponse(localMembers, page, pageSize);
      }
    }

    return dedupe(`groups:members:${key}`, async () => {
      const store = useGroupManagerStore.getState();
      const response = await groupService.getMembers(groupId, page, pageSize);
      const members = response.list || [];
      store.setMembers(groupId, members, page, pageSize);
      if (page === 1) {
        await groupCacheRepository.saveMembers(groupId, members).catch(() => {});
      }
      await userCacheRepository.saveBatch(
        members
          .map((member) => member.user)
          .filter((user): user is NonNullable<typeof user> => Boolean(user))
      ).catch(() => {});
      return response;
    });
  }

  private refreshMembersInBackground(
    groupId: string,
    page = 1,
    pageSize = GROUP_MEMBER_LIST_PAGE_SIZE
  ): void {
    const key = buildMembersKey(groupId, page, pageSize);
    dedupe(`groups:members:bg:${key}`, async () => {
      const store = useGroupManagerStore.getState();
      const response = await groupService.getMembers(groupId, page, pageSize);
      const members = response.list || [];
      store.setMembers(groupId, members, page, pageSize);
      if (page === 1) {
        groupCacheRepository.saveMembers(groupId, members).catch(() => {});
      }
      userCacheRepository.saveBatch(
        members
          .map((member) => member.user)
          .filter((user): user is NonNullable<typeof user> => Boolean(user))
      ).catch(() => {});
      return response;
    }).catch((error) => {
      console.error('[GroupManager] refreshMembersInBackground error:', error);
    });
  }

  createGroupMemberListSource(
    groupId: string,
    kind: RemoteGroupListSourceKind = 'cursor',
    pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE
  ): IGroupMemberListPagedSource {
    return createRemoteGroupMemberListSource(groupId, kind, pageSize);
  }

  invalidate(groupId?: string): void {
    if (!groupId) {
      useGroupManagerStore.getState().invalidateAll();
      return;
    }
    useGroupManagerStore.getState().invalidateGroup(groupId);
  }

  clear(): void {
    useGroupManagerStore.getState().reset();
  }
}

export const groupManager = new GroupManager();

export { GroupManager };

export default groupManager;