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

export type ActivityTemplateStatus = "archived" | "disabled" | "draft" | "published";
export type ActivityTemplateLifecycle = "archived" | "disabled" | "draft" | "ended" | "ongoing" | "scheduled";
export type ActivityTaskType = "daily_visit" | "gift_coin_amount" | "gift_count";
export type ActivityBoardType = "daily" | "total";

export interface ActivityTemplateRewardItemDto {
    durationMs: number;
    iconUrl: string;
    itemType: string;
    name: string;
    quantity: number;
    resourceId: number;
    resourceType: string;
    sortOrder: number;
    walletAssetAmount: number;
    walletAssetType: string;
}

export interface ActivityTemplateLocaleDto {
    locale: string;
    rules: string;
    title: string;
}

export interface ActivityTemplateGiftDto {
    coinPrice: number;
    giftId: string;
    iconUrl: string;
    name: string;
    priceVersion: string;
    sortOrder: number;
}

export interface ActivityTemplateTaskDto {
    rewardItems?: ActivityTemplateRewardItemDto[];
    rewardName?: string;
    rewardResourceGroupId: number;
    rewardSnapshotHash?: string;
    rewardSnapshotId?: string;
    sortOrder: number;
    targetValue: number;
    taskKey: string;
    taskType: ActivityTaskType;
}

export interface ActivityTemplateRankRewardDto {
    boardType: ActivityBoardType;
    rankFrom: number;
    rankTo: number;
    resourceGroupId: number;
    rewardItems?: ActivityTemplateRewardItemDto[];
    rewardName?: string;
    rewardSnapshotHash?: string;
    rewardSnapshotId?: string;
    sortOrder: number;
}

export interface ActivityTemplateAssetDto {
    assetKey: string;
    locale: string;
    mediaType: "image" | "pag" | "svga" | "webp" | string;
    sortOrder: number;
    url: string;
}

export interface ActivityTemplateSummaryDto {
    allRegions: boolean;
    appCode?: string;
    activityType: string;
    createdAtMs?: number;
    createdByAdminId?: number;
    endMs: number;
    lifecycleStatus: ActivityTemplateLifecycle | string;
    name: string;
    publishedVersion: number;
    regionIds: number[];
    revision: number;
    startMs: number;
    status: ActivityTemplateStatus | string;
    templateCode: string;
    templateId: string;
    updatedAtMs?: number;
    updatedByAdminId?: number;
}

export interface ActivityTemplateDto extends ActivityTemplateSummaryDto {
    archivedAtMs?: number;
    assets: ActivityTemplateAssetDto[];
    dailyLeaderboardSize: number;
    displayConfigJson: string;
    gifts: ActivityTemplateGiftDto[];
    locales: ActivityTemplateLocaleDto[];
    publishedAtMs?: number;
    publishedByAdminId?: number;
    rankRewards: ActivityTemplateRankRewardDto[];
    tasks: ActivityTemplateTaskDto[];
    totalLeaderboardSize: number;
}

export interface ActivityTemplateVersionDto {
    publishedAtMs: number;
    publishedByAdminId: number;
    runtimeFromMs: number;
    runtimeToMs: number;
    snapshot: ActivityTemplateDto;
    templateId: string;
    versionNo: number;
}

export interface ActivityTemplateValidationIssueDto {
    code: string;
    field: string;
    message: string;
}

export interface ActivityTemplateValidationResultDto {
    issues: ActivityTemplateValidationIssueDto[];
    valid: boolean;
}

export interface ActivityTemplateDataOverviewDto {
    templateId: string;
    templateCode: string;
    publishedVersion: number;
    participants: number;
    visitCount: number;
    giftUsers: number;
    taskUsers: number;
    giftEventCount: number;
    giftCount: number;
    coinAmount: number;
    taskProgress: number;
    taskCompleted: number;
    taskClaimed: number;
}

export interface ActivityTemplateDataTrendDto {
    statDay: string;
    participants: number;
    visitCount: number;
    giftUsers: number;
    taskUsers: number;
    giftEventCount: number;
    giftCount: number;
    coinAmount: number;
    taskProgress: number;
    taskCompleted: number;
    taskClaimed: number;
}

export interface ActivityTemplateGiftStatDto {
    giftId: string;
    giftUsers: number;
    giftEventCount: number;
    giftCount: number;
    coinAmount: number;
}

export interface ActivityTemplateTaskStatDto {
    taskKey: string;
    taskType: string;
    taskUsers: number;
    taskProgress: number;
    taskCompleted: number;
    taskClaimed: number;
}

export interface ActivityTemplateDataDto {
    overview: ActivityTemplateDataOverviewDto;
    trend: ActivityTemplateDataTrendDto[];
    gifts: ActivityTemplateGiftStatDto[];
    tasks: ActivityTemplateTaskStatDto[];
    granularity: string;
    timezone: string;
    startMs: number;
    endMs: number;
    regionId: number;
    dimensionLimit: number;
    giftSort: string;
    taskSort: string;
    serverTimeMs: number;
}

export interface ActivityTemplateRankPeriodDto {
    templateId: string;
    templateCode: string;
    versionNo: number;
    boardType: ActivityBoardType | string;
    periodKey: string;
    periodStartMs: number;
    periodEndMs: number;
    settleAfterMs: number;
    status: string;
    settledAtMs: number;
}

export interface ActivityTemplateUserDto {
    displayUserId: string;
    username: string;
    avatar: string;
}

export interface ActivityTemplateLeaderboardEntryDto {
    rankNo: number;
    userId: number;
    score: number;
    giftCount: number;
    coinAmount: number;
    firstScoredAtMs: number;
    snapshot: boolean;
    user?: ActivityTemplateUserDto;
}

export interface ActivityTemplateLeaderboardPageDto extends ApiPage<ActivityTemplateLeaderboardEntryDto> {
    period: ActivityTemplateRankPeriodDto;
}

export interface ActivityTemplateRewardJobDto {
    rewardJobId: string;
    templateId: string;
    templateCode: string;
    versionNo: number;
    boardType: ActivityBoardType | string;
    periodKey: string;
    rankNo: number;
    userId: number;
    score: number;
    resourceGroupId: number;
    rewardItems: ActivityTemplateRewardItemDto[];
    rewardName: string;
    rewardSnapshotHash: string;
    rewardSnapshotId: string;
    walletCommandId: string;
    walletGrantId: string;
    status: string;
    failureReason: string;
    attemptCount: number;
    maxAttempts: number;
    nextRetryAtMs: number;
    createdAtMs: number;
    updatedAtMs: number;
    grantedAtMs: number;
    user?: ActivityTemplateUserDto;
}

export interface ActivityTemplateTaskClaimDto {
    attributionAtMs: number;
    claimId: string;
    earningRegionId: number;
    failureReason: string;
    grantedAtMs: number;
    rewardItems: ActivityTemplateRewardItemDto[];
    rewardName: string;
    rewardResourceGroupId: number;
    rewardSnapshotHash: string;
    rewardSnapshotId: string;
    status: string;
    taskDay: string;
    taskKey: string;
    templateCode: string;
    templateId: string;
    updatedAtMs: number;
    createdAtMs: number;
    attemptCount: number;
    user?: ActivityTemplateUserDto;
    userId: number;
    versionNo: number;
    walletGrantId: string;
}

export interface ActivityTemplatePayload {
    activity_type: "gift_challenge";
    all_regions: boolean;
    assets: Array<{
        asset_key: string;
        locale: string;
        media_type: string;
        sort_order: number;
        url: string;
    }>;
    daily_leaderboard_size: number;
    display_config_json: string;
    end_ms: number;
    gifts: Array<{
        coin_price: number;
        gift_id: string;
        icon_url: string;
        name: string;
        price_version: string;
        sort_order: number;
    }>;
    locales: Array<{ locale: string; rules: string; title: string }>;
    name: string;
    rank_rewards: Array<{
        board_type: ActivityBoardType;
        rank_from: number;
        rank_to: number;
        resource_group_id: number;
        sort_order: number;
    }>;
    region_ids: number[];
    start_ms: number;
    tasks: Array<{
        reward_resource_group_id: number;
        sort_order: number;
        target_value: number;
        task_key: string;
        task_type: ActivityTaskType;
    }>;
    template_code: string;
    total_leaderboard_size: number;
}

type RawRecord = Record<string, unknown>;

export function listActivityTemplates(query: PageQuery = {}): Promise<ApiPage<ActivityTemplateSummaryDto>> {
    const endpoint = API_ENDPOINTS.listActivityTemplates;
    return apiRequest<RawRecord>(apiEndpointPath(API_OPERATIONS.listActivityTemplates), {
        method: endpoint.method,
        query,
    }).then((result) => ({
        items: arrayValue(result.templates ?? result.items).map(normalizeSummary),
        page: numberValue(result.page ?? query.page, 1),
        pageSize: numberValue(result.page_size ?? result.pageSize ?? query.page_size ?? query.pageSize, 20),
        total: numberValue(result.total),
    }));
}

export function createActivityTemplate(payload: ActivityTemplatePayload): Promise<ActivityTemplateDto> {
    const endpoint = API_ENDPOINTS.createActivityTemplate;
    return apiRequest<RawRecord, ActivityTemplatePayload>(apiEndpointPath(API_OPERATIONS.createActivityTemplate), {
        body: payload,
        method: endpoint.method,
    }).then((result) => normalizeTemplate(recordValue(result.template ?? result)));
}

export function getActivityTemplate(templateId: EntityId): Promise<ActivityTemplateDto> {
    const endpoint = API_ENDPOINTS.getActivityTemplate;
    return apiRequest<RawRecord>(apiEndpointPath(API_OPERATIONS.getActivityTemplate, { template_id: templateId }), {
        method: endpoint.method,
    }).then((result) => normalizeTemplate(recordValue(result.template ?? result)));
}

export function updateActivityTemplate(
    templateId: EntityId,
    template: ActivityTemplatePayload,
    expectedRevision: number,
): Promise<ActivityTemplateDto> {
    const endpoint = API_ENDPOINTS.updateActivityTemplate;
    return apiRequest<RawRecord, ActivityTemplatePayload & { expected_revision: number }>(
        apiEndpointPath(API_OPERATIONS.updateActivityTemplate, { template_id: templateId }),
        {
            body: { ...template, expected_revision: expectedRevision },
            method: endpoint.method,
        },
    ).then((result) => normalizeTemplate(recordValue(result.template ?? result)));
}

export function setActivityTemplateStatus(
    templateId: EntityId,
    status: "disabled" | "published",
    expectedRevision: number,
): Promise<ActivityTemplateDto> {
    const endpoint = API_ENDPOINTS.setActivityTemplateStatus;
    return apiRequest<RawRecord, { expected_revision: number; status: string }>(
        apiEndpointPath(API_OPERATIONS.setActivityTemplateStatus, { template_id: templateId }),
        {
            body: { expected_revision: expectedRevision, status },
            method: endpoint.method,
        },
    ).then((result) => normalizeTemplate(recordValue(result.template ?? result)));
}

export function deleteActivityTemplate(templateId: EntityId, expectedRevision: number): Promise<ActivityTemplateDto> {
    const endpoint = API_ENDPOINTS.deleteActivityTemplate;
    return apiRequest<RawRecord>(apiEndpointPath(API_OPERATIONS.deleteActivityTemplate, { template_id: templateId }), {
        method: endpoint.method,
        query: { revision: expectedRevision },
    }).then((result) => normalizeTemplate(recordValue(result.template ?? result)));
}

export function cloneActivityTemplate(
    templateId: EntityId,
    payload: { name: string; source_version: number; template_code: string },
): Promise<ActivityTemplateDto> {
    const endpoint = API_ENDPOINTS.cloneActivityTemplate;
    return apiRequest<RawRecord, typeof payload>(
        apiEndpointPath(API_OPERATIONS.cloneActivityTemplate, { template_id: templateId }),
        { body: payload, method: endpoint.method },
    ).then((result) => normalizeTemplate(recordValue(result.template ?? result)));
}

export function listActivityTemplateVersions(
    templateId: EntityId,
    query: PageQuery = {},
): Promise<ApiPage<ActivityTemplateVersionDto>> {
    const endpoint = API_ENDPOINTS.listActivityTemplateVersions;
    return apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.listActivityTemplateVersions, { template_id: templateId }),
        { method: endpoint.method, query },
    ).then((result) => ({
        items: arrayValue(result.versions ?? result.items).map(normalizeVersion),
        page: numberValue(result.page ?? query.page, 1),
        pageSize: numberValue(result.page_size ?? result.pageSize ?? query.page_size ?? query.pageSize, 20),
        total: numberValue(result.total),
    }));
}

export function validateActivityTemplate(
    template: ActivityTemplatePayload,
    forPublish: boolean,
): Promise<ActivityTemplateValidationResultDto> {
    const endpoint = API_ENDPOINTS.validateActivityTemplate;
    return apiRequest<RawRecord, { for_publish: boolean; template: ActivityTemplatePayload }>(
        apiEndpointPath(API_OPERATIONS.validateActivityTemplate),
        {
            body: { for_publish: forPublish, template },
            method: endpoint.method,
        },
    ).then((result) => ({
        issues: arrayValue(result.issues).map((item) => {
            const issue = recordValue(item);
            return {
                code: stringValue(issue.code),
                field: stringValue(issue.field),
                message: stringValue(issue.message),
            };
        }),
        valid: Boolean(result.valid),
    }));
}

export function getActivityTemplateData(
    templateId: EntityId,
    query: { end_ms: number; region_id?: EntityId; start_ms: number; version_no: number },
): Promise<ActivityTemplateDataDto> {
    const endpoint = API_ENDPOINTS.getActivityTemplateData;
    return apiRequest<RawRecord>(apiEndpointPath(API_OPERATIONS.getActivityTemplateData, { template_id: templateId }), {
        method: endpoint.method,
        query,
    }).then(normalizeActivityTemplateData);
}

export function exportActivityTemplateData(
    templateId: EntityId,
    query: { end_ms: number; region_id?: EntityId; start_ms: number; version_no: number },
): Promise<ActivityTemplateDataDto> {
    const endpoint = API_ENDPOINTS.exportActivityTemplateData;
    return apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.exportActivityTemplateData, { template_id: templateId }),
        { method: endpoint.method, query },
    ).then(normalizeActivityTemplateData);
}

export function listActivityTemplateLeaderboard(
    templateId: EntityId,
    query: {
        board_type: ActivityBoardType;
        page?: number;
        page_size?: number;
        period_key?: string;
        version_no: number;
    },
): Promise<ActivityTemplateLeaderboardPageDto> {
    const endpoint = API_ENDPOINTS.listActivityTemplateLeaderboard;
    return apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.listActivityTemplateLeaderboard, { template_id: templateId }),
        { method: endpoint.method, query },
    ).then((result) => ({
        items: arrayValue(result.items).map(normalizeLeaderboardEntry),
        page: numberValue(result.page ?? query.page, 1),
        pageSize: numberValue(result.page_size ?? result.pageSize ?? query.page_size, 20),
        period: normalizeRankPeriod(result.period),
        total: numberValue(result.total),
    }));
}

export function listActivityTemplateRewardJobs(
    templateId: EntityId,
    query: {
        board_type?: ActivityBoardType;
        page?: number;
        page_size?: number;
        period_key?: string;
        status?: string;
        version_no: number;
    },
): Promise<ApiPage<ActivityTemplateRewardJobDto>> {
    const endpoint = API_ENDPOINTS.listActivityTemplateRewardJobs;
    return apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.listActivityTemplateRewardJobs, { template_id: templateId }),
        { method: endpoint.method, query },
    ).then((result) => ({
        items: arrayValue(result.items).map(normalizeRewardJob),
        page: numberValue(result.page ?? query.page, 1),
        pageSize: numberValue(result.page_size ?? result.pageSize ?? query.page_size, 20),
        total: numberValue(result.total),
    }));
}

export function retryActivityTemplateRewardJob(
    templateId: EntityId,
    rewardJobId: EntityId,
): Promise<ActivityTemplateRewardJobDto> {
    const endpoint = API_ENDPOINTS.retryActivityTemplateRewardJob;
    return apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.retryActivityTemplateRewardJob, {
            reward_job_id: rewardJobId,
            template_id: templateId,
        }),
        { method: endpoint.method },
    ).then(normalizeRewardJob);
}

export function listActivityTemplateTaskClaims(
    templateId: EntityId,
    query: {
        page?: number;
        page_size?: number;
        status?: string;
        task_day?: string;
        task_key?: string;
        user_id?: EntityId;
        version_no: number;
    },
): Promise<ApiPage<ActivityTemplateTaskClaimDto>> {
    const endpoint = API_ENDPOINTS.listActivityTemplateTaskClaims;
    return apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.listActivityTemplateTaskClaims, { template_id: templateId }),
        { method: endpoint.method, query },
    ).then((result) => ({
        items: arrayValue(result.items).map(normalizeTaskClaim),
        page: numberValue(result.page ?? query.page, 1),
        pageSize: numberValue(result.page_size ?? result.pageSize ?? query.page_size, 20),
        total: numberValue(result.total),
    }));
}

export function retryActivityTemplateTaskClaim(
    templateId: EntityId,
    claimId: EntityId,
): Promise<ActivityTemplateTaskClaimDto> {
    const endpoint = API_ENDPOINTS.retryActivityTemplateTaskClaim;
    return apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.retryActivityTemplateTaskClaim, {
            claim_id: claimId,
            template_id: templateId,
        }),
        { method: endpoint.method },
    ).then(normalizeTaskClaim);
}

function normalizeSummary(value: unknown): ActivityTemplateSummaryDto {
    const item = recordValue(value);
    return {
        activityType: stringValue(item.activity_type ?? item.activityType, "gift_challenge"),
        allRegions: Boolean(item.all_regions ?? item.allRegions),
        appCode: stringValue(item.app_code ?? item.appCode),
        createdAtMs: numberValue(item.created_at_ms ?? item.createdAtMs),
        createdByAdminId: numberValue(item.created_by_admin_id ?? item.createdByAdminId),
        endMs: numberValue(item.end_ms ?? item.endMs),
        lifecycleStatus: stringValue(item.lifecycle_status ?? item.lifecycleStatus, "draft"),
        name: stringValue(item.name),
        publishedVersion: numberValue(item.published_version ?? item.publishedVersion),
        regionIds: arrayValue(item.region_ids ?? item.regionIds).map((regionId) => numberValue(regionId)),
        revision: numberValue(item.revision),
        startMs: numberValue(item.start_ms ?? item.startMs),
        status: stringValue(item.status, "draft"),
        templateCode: stringValue(item.template_code ?? item.templateCode),
        templateId: stringValue(item.template_id ?? item.templateId),
        updatedAtMs: numberValue(item.updated_at_ms ?? item.updatedAtMs),
        updatedByAdminId: numberValue(item.updated_by_admin_id ?? item.updatedByAdminId),
    };
}

function normalizeTemplate(value: unknown): ActivityTemplateDto {
    const item = recordValue(value);
    return {
        ...normalizeSummary(item),
        archivedAtMs: numberValue(item.archived_at_ms ?? item.archivedAtMs),
        assets: arrayValue(item.assets).map((value) => {
            const asset = recordValue(value);
            return {
                assetKey: stringValue(asset.asset_key ?? asset.assetKey),
                locale: stringValue(asset.locale, "*"),
                mediaType: stringValue(asset.media_type ?? asset.mediaType, "image"),
                sortOrder: numberValue(asset.sort_order ?? asset.sortOrder),
                url: stringValue(asset.url),
            };
        }),
        dailyLeaderboardSize: numberValue(item.daily_leaderboard_size ?? item.dailyLeaderboardSize, 100),
        displayConfigJson: stringValue(item.display_config_json ?? item.displayConfigJson, "{}"),
        gifts: arrayValue(item.gifts).map((value) => {
            const gift = recordValue(value);
            return {
                coinPrice: numberValue(gift.coin_price ?? gift.coinPrice),
                giftId: stringValue(gift.gift_id ?? gift.giftId),
                iconUrl: stringValue(gift.icon_url ?? gift.iconUrl),
                name: stringValue(gift.name),
                priceVersion: stringValue(gift.price_version ?? gift.priceVersion),
                sortOrder: numberValue(gift.sort_order ?? gift.sortOrder),
            };
        }),
        locales: arrayValue(item.locales).map((value) => {
            const locale = recordValue(value);
            return {
                locale: stringValue(locale.locale),
                rules: stringValue(locale.rules),
                title: stringValue(locale.title),
            };
        }),
        publishedAtMs: numberValue(item.published_at_ms ?? item.publishedAtMs),
        publishedByAdminId: numberValue(item.published_by_admin_id ?? item.publishedByAdminId),
        rankRewards: arrayValue(item.rank_rewards ?? item.rankRewards).map((value) => {
            const reward = recordValue(value);
            return {
                boardType: stringValue(reward.board_type ?? reward.boardType, "daily") as ActivityBoardType,
                rankFrom: numberValue(reward.rank_from ?? reward.rankFrom),
                rankTo: numberValue(reward.rank_to ?? reward.rankTo),
                resourceGroupId: numberValue(reward.resource_group_id ?? reward.resourceGroupId),
                rewardItems: arrayValue(reward.reward_items ?? reward.rewardItems).map(normalizeRewardItem),
                rewardName: stringValue(reward.reward_name ?? reward.rewardName),
                rewardSnapshotHash: stringValue(reward.reward_snapshot_hash ?? reward.rewardSnapshotHash),
                rewardSnapshotId: stringValue(reward.reward_snapshot_id ?? reward.rewardSnapshotId),
                sortOrder: numberValue(reward.sort_order ?? reward.sortOrder),
            };
        }),
        tasks: arrayValue(item.tasks).map((value) => {
            const task = recordValue(value);
            return {
                rewardResourceGroupId: numberValue(task.reward_resource_group_id ?? task.rewardResourceGroupId),
                rewardItems: arrayValue(task.reward_items ?? task.rewardItems).map(normalizeRewardItem),
                rewardName: stringValue(task.reward_name ?? task.rewardName),
                rewardSnapshotHash: stringValue(task.reward_snapshot_hash ?? task.rewardSnapshotHash),
                rewardSnapshotId: stringValue(task.reward_snapshot_id ?? task.rewardSnapshotId),
                sortOrder: numberValue(task.sort_order ?? task.sortOrder),
                targetValue: numberValue(task.target_value ?? task.targetValue),
                taskKey: stringValue(task.task_key ?? task.taskKey),
                taskType: stringValue(task.task_type ?? task.taskType, "daily_visit") as ActivityTaskType,
            };
        }),
        totalLeaderboardSize: numberValue(item.total_leaderboard_size ?? item.totalLeaderboardSize, 100),
    };
}

function normalizeVersion(value: unknown): ActivityTemplateVersionDto {
    const item = recordValue(value);
    return {
        publishedAtMs: numberValue(item.published_at_ms ?? item.publishedAtMs),
        publishedByAdminId: numberValue(item.published_by_admin_id ?? item.publishedByAdminId),
        runtimeFromMs: numberValue(item.runtime_from_ms ?? item.runtimeFromMs),
        runtimeToMs: numberValue(item.runtime_to_ms ?? item.runtimeToMs),
        snapshot: normalizeTemplate(item.snapshot),
        templateId: stringValue(item.template_id ?? item.templateId),
        versionNo: numberValue(item.version_no ?? item.versionNo),
    };
}

function normalizeActivityTemplateData(value: unknown): ActivityTemplateDataDto {
    const item = recordValue(value);
    const overview = recordValue(item.overview);
    return {
        overview: {
            templateId: stringValue(overview.template_id ?? overview.templateId),
            templateCode: stringValue(overview.template_code ?? overview.templateCode),
            publishedVersion: numberValue(overview.published_version ?? overview.publishedVersion),
            participants: numberValue(overview.participants),
            visitCount: numberValue(overview.visit_count ?? overview.visitCount),
            giftUsers: numberValue(overview.gift_users ?? overview.giftUsers),
            taskUsers: numberValue(overview.task_users ?? overview.taskUsers),
            giftEventCount: numberValue(overview.gift_event_count ?? overview.giftEventCount),
            giftCount: numberValue(overview.gift_count ?? overview.giftCount),
            coinAmount: numberValue(overview.coin_amount ?? overview.coinAmount),
            taskProgress: numberValue(overview.task_progress ?? overview.taskProgress),
            taskCompleted: numberValue(overview.task_completed ?? overview.taskCompleted),
            taskClaimed: numberValue(overview.task_claimed ?? overview.taskClaimed),
        },
        trend: arrayValue(item.trend).map((value) => {
            const point = recordValue(value);
            return {
                statDay: stringValue(point.stat_day ?? point.statDay),
                participants: numberValue(point.participants),
                visitCount: numberValue(point.visit_count ?? point.visitCount),
                giftUsers: numberValue(point.gift_users ?? point.giftUsers),
                taskUsers: numberValue(point.task_users ?? point.taskUsers),
                giftEventCount: numberValue(point.gift_event_count ?? point.giftEventCount),
                giftCount: numberValue(point.gift_count ?? point.giftCount),
                coinAmount: numberValue(point.coin_amount ?? point.coinAmount),
                taskProgress: numberValue(point.task_progress ?? point.taskProgress),
                taskCompleted: numberValue(point.task_completed ?? point.taskCompleted),
                taskClaimed: numberValue(point.task_claimed ?? point.taskClaimed),
            };
        }),
        gifts: arrayValue(item.gifts).map((value) => {
            const gift = recordValue(value);
            return {
                giftId: stringValue(gift.gift_id ?? gift.giftId),
                giftUsers: numberValue(gift.gift_users ?? gift.giftUsers),
                giftEventCount: numberValue(gift.gift_event_count ?? gift.giftEventCount),
                giftCount: numberValue(gift.gift_count ?? gift.giftCount),
                coinAmount: numberValue(gift.coin_amount ?? gift.coinAmount),
            };
        }),
        tasks: arrayValue(item.tasks).map((value) => {
            const task = recordValue(value);
            return {
                taskKey: stringValue(task.task_key ?? task.taskKey),
                taskType: stringValue(task.task_type ?? task.taskType),
                taskUsers: numberValue(task.task_users ?? task.taskUsers),
                taskProgress: numberValue(task.task_progress ?? task.taskProgress),
                taskCompleted: numberValue(task.task_completed ?? task.taskCompleted),
                taskClaimed: numberValue(task.task_claimed ?? task.taskClaimed),
            };
        }),
        granularity: stringValue(item.granularity, "day"),
        timezone: stringValue(item.timezone, "UTC"),
        startMs: numberValue(item.start_ms ?? item.startMs),
        endMs: numberValue(item.end_ms ?? item.endMs),
        regionId: numberValue(item.region_id ?? item.regionId),
        dimensionLimit: numberValue(item.dimension_limit ?? item.dimensionLimit),
        giftSort: stringValue(item.gift_sort ?? item.giftSort),
        taskSort: stringValue(item.task_sort ?? item.taskSort),
        serverTimeMs: numberValue(item.server_time_ms ?? item.serverTimeMs),
    };
}

function normalizeRankPeriod(value: unknown): ActivityTemplateRankPeriodDto {
    const item = recordValue(value);
    return {
        templateId: stringValue(item.template_id ?? item.templateId),
        templateCode: stringValue(item.template_code ?? item.templateCode),
        versionNo: numberValue(item.version_no ?? item.versionNo),
        boardType: stringValue(item.board_type ?? item.boardType),
        periodKey: stringValue(item.period_key ?? item.periodKey),
        periodStartMs: numberValue(item.period_start_ms ?? item.periodStartMs),
        periodEndMs: numberValue(item.period_end_ms ?? item.periodEndMs),
        settleAfterMs: numberValue(item.settle_after_ms ?? item.settleAfterMs),
        status: stringValue(item.status),
        settledAtMs: numberValue(item.settled_at_ms ?? item.settledAtMs),
    };
}

function normalizeLeaderboardEntry(value: unknown): ActivityTemplateLeaderboardEntryDto {
    const item = recordValue(value);
    return {
        rankNo: numberValue(item.rank_no ?? item.rankNo),
        userId: numberValue(item.user_id ?? item.userId),
        score: numberValue(item.score),
        giftCount: numberValue(item.gift_count ?? item.giftCount),
        coinAmount: numberValue(item.coin_amount ?? item.coinAmount),
        firstScoredAtMs: numberValue(item.first_scored_at_ms ?? item.firstScoredAtMs),
        snapshot: Boolean(item.snapshot),
        user: normalizeActivityTemplateUser(item.user),
    };
}

function normalizeRewardJob(value: unknown): ActivityTemplateRewardJobDto {
    const item = recordValue(value);
    return {
        rewardJobId: stringValue(item.reward_job_id ?? item.rewardJobId),
        templateId: stringValue(item.template_id ?? item.templateId),
        templateCode: stringValue(item.template_code ?? item.templateCode),
        versionNo: numberValue(item.version_no ?? item.versionNo),
        boardType: stringValue(item.board_type ?? item.boardType),
        periodKey: stringValue(item.period_key ?? item.periodKey),
        rankNo: numberValue(item.rank_no ?? item.rankNo),
        userId: numberValue(item.user_id ?? item.userId),
        score: numberValue(item.score),
        resourceGroupId: numberValue(item.resource_group_id ?? item.resourceGroupId),
        rewardItems: arrayValue(item.reward_items ?? item.rewardItems).map(normalizeRewardItem),
        rewardName: stringValue(item.reward_name ?? item.rewardName),
        rewardSnapshotHash: stringValue(item.reward_snapshot_hash ?? item.rewardSnapshotHash),
        rewardSnapshotId: stringValue(item.reward_snapshot_id ?? item.rewardSnapshotId),
        walletCommandId: stringValue(item.wallet_command_id ?? item.walletCommandId),
        walletGrantId: stringValue(item.wallet_grant_id ?? item.walletGrantId),
        status: stringValue(item.status),
        failureReason: stringValue(item.failure_reason ?? item.failureReason),
        attemptCount: numberValue(item.attempt_count ?? item.attemptCount),
        maxAttempts: numberValue(item.max_attempts ?? item.maxAttempts),
        nextRetryAtMs: numberValue(item.next_retry_at_ms ?? item.nextRetryAtMs),
        createdAtMs: numberValue(item.created_at_ms ?? item.createdAtMs),
        updatedAtMs: numberValue(item.updated_at_ms ?? item.updatedAtMs),
        grantedAtMs: numberValue(item.granted_at_ms ?? item.grantedAtMs),
        user: normalizeActivityTemplateUser(item.user),
    };
}

function normalizeTaskClaim(value: unknown): ActivityTemplateTaskClaimDto {
    const item = recordValue(value);
    return {
        attributionAtMs: numberValue(item.attribution_at_ms ?? item.attributionAtMs),
        claimId: stringValue(item.claim_id ?? item.claimId),
        earningRegionId: numberValue(item.earning_region_id ?? item.earningRegionId),
        failureReason: stringValue(item.failure_reason ?? item.failureReason),
        grantedAtMs: numberValue(item.granted_at_ms ?? item.grantedAtMs),
        rewardItems: arrayValue(item.reward_items ?? item.rewardItems).map(normalizeRewardItem),
        rewardName: stringValue(item.reward_name ?? item.rewardName),
        rewardResourceGroupId: numberValue(item.reward_resource_group_id ?? item.rewardResourceGroupId),
        rewardSnapshotHash: stringValue(item.reward_snapshot_hash ?? item.rewardSnapshotHash),
        rewardSnapshotId: stringValue(item.reward_snapshot_id ?? item.rewardSnapshotId),
        status: stringValue(item.status),
        taskDay: stringValue(item.task_day ?? item.taskDay),
        taskKey: stringValue(item.task_key ?? item.taskKey),
        templateCode: stringValue(item.template_code ?? item.templateCode),
        templateId: stringValue(item.template_id ?? item.templateId),
        updatedAtMs: numberValue(item.updated_at_ms ?? item.updatedAtMs),
        createdAtMs: numberValue(item.created_at_ms ?? item.createdAtMs),
        attemptCount: numberValue(item.attempt_count ?? item.attemptCount),
        user: normalizeActivityTemplateUser(item.user),
        userId: numberValue(item.user_id ?? item.userId),
        versionNo: numberValue(item.version_no ?? item.versionNo),
        walletGrantId: stringValue(item.wallet_grant_id ?? item.walletGrantId),
    };
}

function normalizeRewardItem(value: unknown): ActivityTemplateRewardItemDto {
    const item = recordValue(value);
    return {
        durationMs: numberValue(item.duration_ms ?? item.durationMs),
        iconUrl: stringValue(item.icon_url ?? item.iconUrl),
        itemType: stringValue(item.item_type ?? item.itemType),
        name: stringValue(item.name),
        quantity: numberValue(item.quantity),
        resourceId: numberValue(item.resource_id ?? item.resourceId),
        resourceType: stringValue(item.resource_type ?? item.resourceType),
        sortOrder: numberValue(item.sort_order ?? item.sortOrder),
        walletAssetAmount: numberValue(item.wallet_asset_amount ?? item.walletAssetAmount),
        walletAssetType: stringValue(item.wallet_asset_type ?? item.walletAssetType),
    };
}

function normalizeActivityTemplateUser(value: unknown): ActivityTemplateUserDto | undefined {
    const item = recordValue(value);
    if (!Object.keys(item).length) return undefined;
    return {
        displayUserId: stringValue(item.display_user_id ?? item.displayUserId),
        username: stringValue(item.username),
        avatar: stringValue(item.avatar),
    };
}

function recordValue(value: unknown): RawRecord {
    return value && typeof value === "object" && !Array.isArray(value) ? (value as RawRecord) : {};
}

function arrayValue(value: unknown): unknown[] {
    return Array.isArray(value) ? value : [];
}

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

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