import { _LinksDTO } from './_linksDTO';
import { SerializationClass } from './serializationClass';

export abstract class PaginatedSerializationClass<ModelType, SerializedType, ExtraData = Record<string, unknown>> extends SerializationClass<
    ModelType,
    SerializedType,
    ExtraData
> {
    public serializePaginatedList = (options: {
        rows: ModelType[];
        limit: number;
        offset: number;
        count: number;
        extraData?: ExtraData;
        rowActions?: {
            id: number;
            actions: string[];
        }[];
    }): PaginatedResponse<SerializedType> => {
        const { rows, limit, offset, count, extraData, rowActions } = options;
        const expectingPage = Math.ceil((offset + 1) / limit);
        const page = isFinite(expectingPage) && expectingPage > 0 ? expectingPage : 1;
        const expectingTotalPages = limit ? Math.ceil(count / limit) : 1;
        const totalPages = isFinite(expectingTotalPages) && expectingTotalPages > 0 ? expectingTotalPages : 1;
        return {
            count,
            items: super.serializeList(rows, extraData),
            limit,
            page,
            totalPages,
            ...(rowActions ? { itemActions: rowActions } : {}),
        };
    };

    public serializePaginatedListWithLinks = (
        options: {
            rows: ModelType[];
            limit: number;
            offset: number;
            count: number;
            extraData?: ExtraData;
        },
        _links: _LinksDTO,
    ): PaginatedResponseWithLinks<SerializedType> => {
        const { rows, limit, offset, count, extraData } = options;
        const expectingPage = Math.ceil((offset + 1) / limit);
        const page = isFinite(expectingPage) && expectingPage > 0 ? expectingPage : 1;
        const expectingTotalPages = limit ? Math.ceil(count / limit) : 1;
        const totalPages = isFinite(expectingTotalPages) && expectingTotalPages > 0 ? expectingTotalPages : 1;
        return {
            _links,
            count,
            items: super.serializeList(rows, extraData),
            limit,
            page,
            totalPages,
        };
    };

    abstract serialize(serializableObject: ModelType, extraData?: ExtraData): SerializedType;
}

export type PaginatedResponse<SerializedType> = {
    limit: number;
    page: number;
    totalPages: number;
    count: number;
    items: SerializedType[];
    itemActions?: {
        id: number;
        actions: string[];
    }[];
};

export type PaginatedResponseWithLinks<SerializedType> = {
    limit: number;
    page: number;
    totalPages: number;
    count: number;
    items: SerializedType[];
    _links: _LinksDTO;
};
