/**
 * 群组数据源抽象：群组列表 + 群组成员列表的游标/偏移分页实现。
 */

import {
  GroupResponse,
  GroupMemberResponse,
  GroupListResponse,
  GroupMemberListResponse,
  CursorPaginationRequest,
  CursorPaginationResponse,
} from '../../types/dto';
import { groupService } from '@/services/message';
import { groupCacheRepository } from '@/database';

export const GROUP_LIST_PAGE_SIZE = 20;
export const GROUP_MEMBER_LIST_PAGE_SIZE = 50;

// ==================== 群组列表数据源 ====================

export interface GroupListPage {
  items: GroupResponse[];
  hasMore: boolean;
}

export interface IGroupListPagedSource {
  restart(): void;
  loadNext(): Promise<GroupListPage>;
  readonly hasMore: boolean;
}

export class NetworkCursorGroupListPagedSource implements IGroupListPagedSource {
  private nextCursor: string | null = null;
  private hasMoreAfterLastLoad = false;
  private loadedOnce = false;
  private readonly pageSize: number;

  constructor(pageSize: number = GROUP_LIST_PAGE_SIZE) {
    this.pageSize = pageSize;
  }

  restart(): void {
    this.nextCursor = null;
    this.hasMoreAfterLastLoad = false;
    this.loadedOnce = false;
  }

  get hasMore(): boolean {
    return this.loadedOnce && this.hasMoreAfterLastLoad;
  }

  async loadNext(): Promise<GroupListPage> {
    const params: CursorPaginationRequest = {
      cursor: this.nextCursor ?? '',
      page_size: this.pageSize,
    };

    const result = await groupService.getGroupsCursor(params);

    this.hasMoreAfterLastLoad = result.has_more ?? false;
    this.nextCursor = result.next_cursor ?? null;
    this.loadedOnce = true;

    return { items: result.list ?? [], hasMore: this.hasMoreAfterLastLoad };
  }
}

export class NetworkOffsetGroupListPagedSource implements IGroupListPagedSource {
  private nextPage = 1;
  private hasMoreAfterLastLoad = false;
  private loadedOnce = false;
  private readonly pageSize: number;

  constructor(pageSize: number = GROUP_LIST_PAGE_SIZE) {
    this.pageSize = pageSize;
  }

  restart(): void {
    this.nextPage = 1;
    this.hasMoreAfterLastLoad = false;
    this.loadedOnce = false;
  }

  get hasMore(): boolean {
    return this.loadedOnce && this.hasMoreAfterLastLoad;
  }

  async loadNext(): Promise<GroupListPage> {
    const result = await groupService.getGroups(this.nextPage, this.pageSize);

    const items = result.list ?? [];
    const totalPages = result.total_pages ?? 1;

    this.hasMoreAfterLastLoad = this.nextPage < totalPages;
    this.nextPage++;
    this.loadedOnce = true;

    return { items, hasMore: this.hasMoreAfterLastLoad };
  }
}

export class SqliteGroupListPagedSource implements IGroupListPagedSource {
  private consumed = false;

  restart(): void {
    this.consumed = false;
  }

  get hasMore(): boolean {
    return false;
  }

  async loadNext(): Promise<GroupListPage> {
    if (this.consumed) {
      return { items: [], hasMore: false };
    }
    this.consumed = true;
    try {
      const items = await groupCacheRepository.getAll();
      return { items, hasMore: false };
    } catch (e) {
      console.warn('[SqliteGroupListPagedSource] 读取群组列表缓存失败:', e);
      return { items: [], hasMore: false };
    }
  }
}

// ==================== 群组成员列表数据源（Manager 内部用） ====================

export interface GroupMemberListPage {
  items: GroupMemberResponse[];
  hasMore: boolean;
}

export interface IGroupMemberListPagedSource {
  restart(): void;
  loadNext(): Promise<GroupMemberListPage>;
  readonly hasMore: boolean;
}

export class NetworkCursorGroupMemberListPagedSource implements IGroupMemberListPagedSource {
  private nextCursor: string | null = null;
  private hasMoreAfterLastLoad = false;
  private loadedOnce = false;
  private readonly pageSize: number;
  private readonly groupId: string;

  constructor(groupId: string, pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE) {
    this.groupId = groupId;
    this.pageSize = pageSize;
  }

  restart(): void {
    this.nextCursor = null;
    this.hasMoreAfterLastLoad = false;
    this.loadedOnce = false;
  }

  get hasMore(): boolean {
    return this.loadedOnce && this.hasMoreAfterLastLoad;
  }

  async loadNext(): Promise<GroupMemberListPage> {
    const params: CursorPaginationRequest = {
      cursor: this.nextCursor ?? '',
      page_size: this.pageSize,
    };

    const result = await groupService.getGroupMembersCursor(this.groupId, params);

    this.hasMoreAfterLastLoad = result.has_more ?? false;
    this.nextCursor = result.next_cursor ?? null;
    this.loadedOnce = true;

    return { items: result.list ?? [], hasMore: this.hasMoreAfterLastLoad };
  }
}

export class NetworkOffsetGroupMemberListPagedSource implements IGroupMemberListPagedSource {
  private nextPage = 1;
  private hasMoreAfterLastLoad = false;
  private loadedOnce = false;
  private readonly pageSize: number;
  private readonly groupId: string;

  constructor(groupId: string, pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE) {
    this.groupId = groupId;
    this.pageSize = pageSize;
  }

  restart(): void {
    this.nextPage = 1;
    this.hasMoreAfterLastLoad = false;
    this.loadedOnce = false;
  }

  get hasMore(): boolean {
    return this.loadedOnce && this.hasMoreAfterLastLoad;
  }

  async loadNext(): Promise<GroupMemberListPage> {
    const result = await groupService.getMembers(
      this.groupId,
      this.nextPage,
      this.pageSize
    );

    const items = result.list ?? [];
    const totalPages = result.total_pages ?? 1;

    this.hasMoreAfterLastLoad = this.nextPage < totalPages;
    this.nextPage++;
    this.loadedOnce = true;

    return { items, hasMore: this.hasMoreAfterLastLoad };
  }
}

export class SqliteGroupMemberListPagedSource implements IGroupMemberListPagedSource {
  private consumed = false;
  private readonly groupId: string;

  constructor(groupId: string) {
    this.groupId = groupId;
  }

  restart(): void {
    this.consumed = false;
  }

  get hasMore(): boolean {
    return false;
  }

  async loadNext(): Promise<GroupMemberListPage> {
    if (this.consumed) {
      return { items: [], hasMore: false };
    }
    this.consumed = true;
    try {
      const items = await groupCacheRepository.getMembers(this.groupId);
      return { items, hasMore: false };
    } catch (e) {
      console.warn('[SqliteGroupMemberListPagedSource] 读取成员列表缓存失败:', e);
      return { items: [], hasMore: false };
    }
  }
}

// ==================== 群组成员列表数据源（Screen 层用，返回 CursorPaginationResponse） ====================

export type GroupMemberListSourceKind = 'cursor' | 'offset';

export interface ICursorGroupMemberListPagedSource {
  restart(): void;
  loadNext(): Promise<CursorPaginationResponse<GroupMemberResponse>>;
  readonly hasMore: boolean;
}

export class CursorGroupMemberListSource implements ICursorGroupMemberListPagedSource {
  private nextCursor: string | null = null;
  private hasMoreAfterLastLoad = false;
  private loadedOnce = false;
  private readonly groupId: string;
  private readonly pageSize: number;

  constructor(groupId: string, pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE) {
    this.groupId = groupId;
    this.pageSize = pageSize;
  }

  restart(): void {
    this.nextCursor = null;
    this.hasMoreAfterLastLoad = false;
    this.loadedOnce = false;
  }

  get hasMore(): boolean {
    return this.loadedOnce && this.hasMoreAfterLastLoad;
  }

  async loadNext(): Promise<CursorPaginationResponse<GroupMemberResponse>> {
    const response = await groupService.getGroupMembersCursor(
      this.groupId,
      this.nextCursor == null
        ? { page_size: this.pageSize }
        : { cursor: this.nextCursor, page_size: this.pageSize }
    );

    this.nextCursor = response.next_cursor ?? null;
    this.hasMoreAfterLastLoad = Boolean(response.has_more && response.next_cursor != null);
    this.loadedOnce = true;

    return {
      list: response.list || [],
      next_cursor: response.next_cursor ?? null,
      prev_cursor: response.prev_cursor ?? null,
      has_more: response.has_more ?? false,
    };
  }
}

export class OffsetGroupMemberListSource implements ICursorGroupMemberListPagedSource {
  private nextPage = 1;
  private hasMoreAfterLastLoad = false;
  private loadedOnce = false;
  private readonly groupId: string;
  private readonly pageSize: number;

  constructor(groupId: string, pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE) {
    this.groupId = groupId;
    this.pageSize = pageSize;
  }

  restart(): void {
    this.nextPage = 1;
    this.hasMoreAfterLastLoad = false;
    this.loadedOnce = false;
  }

  get hasMore(): boolean {
    return this.loadedOnce && this.hasMoreAfterLastLoad;
  }

  async loadNext(): Promise<CursorPaginationResponse<GroupMemberResponse>> {
    const response = await groupService.getMembers(this.groupId, this.nextPage, this.pageSize);
    const list = response.list || [];
    const currentPage = response.page ?? this.nextPage;
    const totalPages = response.total_pages ?? currentPage;
    const hasMore = currentPage < totalPages;
    const nextPageCursor = hasMore ? String(currentPage + 1) : null;
    const prevPageCursor = currentPage > 1 ? String(currentPage - 1) : null;

    this.nextPage = currentPage + 1;
    this.hasMoreAfterLastLoad = hasMore;
    this.loadedOnce = true;

    return {
      list,
      next_cursor: nextPageCursor,
      prev_cursor: prevPageCursor,
      has_more: hasMore,
    };
  }
}

export function createCursorGroupMemberListSource(
  kind: GroupMemberListSourceKind,
  groupId: string,
  pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE
): ICursorGroupMemberListPagedSource {
  return kind === 'offset'
    ? new OffsetGroupMemberListSource(groupId, pageSize)
    : new CursorGroupMemberListSource(groupId, pageSize);
}

// ==================== 工厂函数 ====================

export type RemoteGroupListSourceKind = 'cursor' | 'offset';

export function createRemoteGroupListSource(
  kind: RemoteGroupListSourceKind = 'cursor',
  pageSize: number = GROUP_LIST_PAGE_SIZE
): IGroupListPagedSource {
  if (kind === 'offset') {
    return new NetworkOffsetGroupListPagedSource(pageSize);
  }
  return new NetworkCursorGroupListPagedSource(pageSize);
}

export function createRemoteGroupMemberListSource(
  groupId: string,
  kind: RemoteGroupListSourceKind = 'cursor',
  pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE
): IGroupMemberListPagedSource {
  if (kind === 'offset') {
    return new NetworkOffsetGroupMemberListPagedSource(groupId, pageSize);
  }
  return new NetworkCursorGroupMemberListPagedSource(groupId, pageSize);
}
