import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
import { apiRequest } from "@/shared/api/request";
import type { PageQuery } from "@/shared/api/types";

export type UserLeaderboardBoardType = "sent" | "received" | "room";
export type UserLeaderboardPeriod = "today" | "week" | "month";

export interface UserLeaderboardUserDto {
    userId: string;
    displayUserId?: string;
    prettyDisplayUserId?: string;
    prettyId?: string;
    username?: string;
    avatar?: string;
}

export interface UserLeaderboardRoomDto {
    roomId: string;
    roomShortId?: string;
    title?: string;
    coverUrl?: string;
    ownerUserId?: string;
    status?: string;
}

export interface UserLeaderboardItemDto {
    rank: number;
    userId?: string;
    roomId?: string;
    giftValue: number;
    giftCount: number;
    transactionCount: number;
    lastGiftAtMs: number;
    user?: UserLeaderboardUserDto;
    room?: UserLeaderboardRoomDto;
}

export interface UserLeaderboardResponseDto {
    items: UserLeaderboardItemDto[];
    total: number;
    page: number;
    pageSize: number;
    boardType: UserLeaderboardBoardType;
    period: UserLeaderboardPeriod;
    startAtMs: number;
    endAtMs: number;
    serverTimeMs: number;
    myRank?: UserLeaderboardItemDto | null;
}

export interface UserLeaderboardQuery extends PageQuery {
    board_type?: UserLeaderboardBoardType;
    period?: UserLeaderboardPeriod;
    viewer_user_id?: string;
}

type RawUser = UserLeaderboardUserDto & Record<string, unknown>;
type RawRoom = UserLeaderboardRoomDto & Record<string, unknown>;
type RawItem = Omit<UserLeaderboardItemDto, "room" | "user"> & {
    last_gift_at_ms?: number | string;
    transaction_count?: number | string;
    gift_count?: number | string;
    gift_value?: number | string;
    user_id?: string | number;
    room_id?: string;
    user?: RawUser;
    room?: RawRoom;
} & Record<string, unknown>;
type RawResponse = Omit<UserLeaderboardResponseDto, "items" | "myRank"> & {
    board_type?: UserLeaderboardBoardType;
    end_at_ms?: number | string;
    items?: RawItem[];
    my_rank?: RawItem | null;
    myRank?: RawItem | null;
    page_size?: number | string;
    server_time_ms?: number | string;
    start_at_ms?: number | string;
} & Record<string, unknown>;

export function listUserLeaderboards(query: UserLeaderboardQuery = {}): Promise<UserLeaderboardResponseDto> {
    const endpoint = API_ENDPOINTS.listUserLeaderboards;
    return apiRequest<RawResponse>(apiEndpointPath(API_OPERATIONS.listUserLeaderboards), {
        method: endpoint.method,
        query,
    }).then(normalizeResponse);
}

function normalizeResponse(response: RawResponse): UserLeaderboardResponseDto {
    return {
        items: (response.items || []).map(normalizeItem),
        total: numberValue(response.total),
        page: numberValue(response.page) || 1,
        pageSize: numberValue(response.pageSize ?? response.page_size) || 20,
        boardType: normalizeBoardType(response.boardType ?? response.board_type),
        period: normalizePeriod(response.period),
        startAtMs: numberValue(response.startAtMs ?? response.start_at_ms),
        endAtMs: numberValue(response.endAtMs ?? response.end_at_ms),
        serverTimeMs: numberValue(response.serverTimeMs ?? response.server_time_ms),
        myRank:
            response.myRank || response.my_rank
                ? normalizeItem((response.myRank || response.my_rank) as RawItem)
                : null,
    };
}

function normalizeItem(item: RawItem): UserLeaderboardItemDto {
    return {
        rank: numberValue(item.rank),
        userId: optionalString(item.userId ?? item.user_id),
        roomId: optionalString(item.roomId ?? item.room_id),
        giftValue: numberValue(item.giftValue ?? item.gift_value),
        giftCount: numberValue(item.giftCount ?? item.gift_count),
        transactionCount: numberValue(item.transactionCount ?? item.transaction_count),
        lastGiftAtMs: numberValue(item.lastGiftAtMs ?? item.last_gift_at_ms),
        user: item.user ? normalizeUser(item.user) : undefined,
        room: item.room ? normalizeRoom(item.room) : undefined,
    };
}

function normalizeUser(user: RawUser): UserLeaderboardUserDto {
    return {
        userId: stringValue(user.userId ?? user.user_id),
        displayUserId: optionalString(user.displayUserId ?? user.display_user_id),
        prettyDisplayUserId: optionalString(user.prettyDisplayUserId ?? user.pretty_display_user_id),
        prettyId: optionalString(user.prettyId ?? user.pretty_id),
        username: optionalString(user.username),
        avatar: optionalString(user.avatar),
    };
}

function normalizeRoom(room: RawRoom): UserLeaderboardRoomDto {
    return {
        roomId: stringValue(room.roomId ?? room.room_id),
        roomShortId: optionalString(room.roomShortId ?? room.room_short_id),
        title: optionalString(room.title),
        coverUrl: optionalString(room.coverUrl ?? room.cover_url),
        ownerUserId: optionalString(room.ownerUserId ?? room.owner_user_id),
        status: optionalString(room.status),
    };
}

function normalizeBoardType(value: unknown): UserLeaderboardBoardType {
    return value === "received" || value === "room" ? value : "sent";
}

function normalizePeriod(value: unknown): UserLeaderboardPeriod {
    return value === "week" || value === "month" ? value : "today";
}

function stringValue(value: unknown) {
    return value === null || value === undefined ? "" : String(value);
}

function optionalString(value: unknown) {
    const text = stringValue(value).trim();
    return text || undefined;
}

function numberValue(value: unknown) {
    const next = Number(value ?? 0);
    return Number.isFinite(next) ? next : 0;
}
