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

export type LevelTrackCode = "wealth" | "game" | "charm";
export type LevelConfigStatus = "active" | "disabled";

export interface LevelRuleDto {
    createdAtMs?: number;
    displayConfigJson?: string;
    level: number;
    avatarFrameResourceId?: number;
    longBadgeResourceId?: number;
    name?: string;
    requiredValue: number;
    rewardResourceGroupId?: number;
    shortBadgeResourceId?: number;
    sortOrder?: number;
    status?: LevelConfigStatus | string;
    track: LevelTrackCode;
    updatedAtMs?: number;
}

export interface LevelTierDto {
    createdAtMs?: number;
    displayAvatarFrameResourceId?: number;
    displayBadgeResourceId?: number;
    displayConfigJson?: string;
    maxLevel: number;
    minLevel: number;
    name?: string;
    rewardResourceGroupId?: number;
    status?: LevelConfigStatus | string;
    tierId: number;
    track: LevelTrackCode;
    updatedAtMs?: number;
}

export interface LevelTrackDto {
    createdAtMs?: number;
    displayConfigJson?: string;
    name?: string;
    rules: LevelRuleDto[];
    sortOrder?: number;
    status?: LevelConfigStatus | string;
    tiers: LevelTierDto[];
    track: LevelTrackCode;
    updatedAtMs?: number;
}

export interface LevelConfigDto {
    serverTimeMs?: number;
    tracks: LevelTrackDto[];
}

export interface LevelTrackPayload {
    display_config_json?: string;
    name: string;
    sort_order: number;
    status: LevelConfigStatus;
}

export interface LevelRulePayload {
    avatar_frame_resource_id?: number;
    long_badge_resource_id?: number;
    name: string;
    required_value: number;
    reward_resource_group_id?: number;
    short_badge_resource_id?: number;
    sort_order: number;
    status: LevelConfigStatus;
}

export interface LevelTierPayload {
    display_avatar_frame_resource_id?: number;
    display_badge_resource_id?: number;
    display_config_json?: string;
    max_level: number;
    min_level: number;
    name: string;
    reward_resource_group_id?: number;
    status: LevelConfigStatus;
    track: LevelTrackCode;
}

export interface BatchLevelRulePayload extends LevelRulePayload {
    level: number;
    track: LevelTrackCode;
}

export interface BatchLevelTierPayload extends LevelTierPayload {
    tier_id: number;
}

export interface BatchLevelConfigPayload {
    rules: BatchLevelRulePayload[];
    tiers: BatchLevelTierPayload[];
}

export interface BatchLevelConfigResult {
    rules: LevelRuleDto[];
    serverTimeMs?: number;
    tiers: LevelTierDto[];
}

type AnyRecord = Record<string, unknown>;

export function listLevelConfig(query: PageQuery = {}): Promise<LevelConfigDto> {
    const endpoint = API_ENDPOINTS.listLevelConfig;
    return apiRequest<unknown>(apiEndpointPath(API_OPERATIONS.listLevelConfig), {
        method: endpoint.method,
        query,
    }).then(normalizeLevelConfig);
}

export function updateTrack(track: LevelTrackCode, payload: LevelTrackPayload): Promise<LevelTrackDto> {
    const endpoint = API_ENDPOINTS.updateTrack;
    return apiRequest<unknown, LevelTrackPayload>(apiEndpointPath(API_OPERATIONS.updateTrack, { track }), {
        body: payload,
        method: endpoint.method,
    }).then(normalizeTrack);
}

export function upsertRule(track: LevelTrackCode, level: EntityId, payload: LevelRulePayload): Promise<LevelRuleDto> {
    const endpoint = API_ENDPOINTS.upsertRule;
    return apiRequest<unknown, LevelRulePayload>(apiEndpointPath(API_OPERATIONS.upsertRule, { level, track }), {
        body: payload,
        method: endpoint.method,
    }).then(normalizeRule);
}

export function createTier(payload: LevelTierPayload): Promise<LevelTierDto> {
    const endpoint = API_ENDPOINTS.createTier;
    return apiRequest<unknown, LevelTierPayload>(apiEndpointPath(API_OPERATIONS.createTier), {
        body: payload,
        method: endpoint.method,
    }).then(normalizeTier);
}

export function updateTier(tierId: EntityId, payload: LevelTierPayload): Promise<LevelTierDto> {
    const endpoint = API_ENDPOINTS.updateTier;
    return apiRequest<unknown, LevelTierPayload>(apiEndpointPath(API_OPERATIONS.updateTier, { tier_id: tierId }), {
        body: payload,
        method: endpoint.method,
    }).then(normalizeTier);
}

export function batchUpsertLevelConfig(payload: BatchLevelConfigPayload): Promise<BatchLevelConfigResult> {
    const endpoint = API_ENDPOINTS.batchUpsertLevelConfig;
    return apiRequest<unknown, BatchLevelConfigPayload>(apiEndpointPath(API_OPERATIONS.batchUpsertLevelConfig), {
        body: payload,
        method: endpoint.method,
    }).then((raw) => {
        const source = asRecord(raw);
        return {
            rules: arrayValue(source.rules).map(normalizeRule),
            serverTimeMs: numberValue(source.serverTimeMs ?? source.server_time_ms),
            tiers: arrayValue(source.tiers).map(normalizeTier),
        };
    });
}

function normalizeLevelConfig(raw: unknown): LevelConfigDto {
    const source = asRecord(raw);
    return {
        serverTimeMs: numberValue(source.serverTimeMs ?? source.server_time_ms),
        tracks: arrayValue(source.tracks).map(normalizeTrack),
    };
}

function normalizeTrack(raw: unknown): LevelTrackDto {
    const source = asRecord(raw);
    return {
        createdAtMs: numberValue(source.createdAtMs ?? source.created_at_ms),
        displayConfigJson: jsonString(source.displayConfigJson ?? source.display_config_json),
        name: stringValue(source.name),
        rules: arrayValue(source.rules).map(normalizeRule),
        sortOrder: numberValue(source.sortOrder ?? source.sort_order),
        status: stringValue(source.status),
        tiers: arrayValue(source.tiers).map(normalizeTier),
        track: stringValue(source.track) as LevelTrackCode,
        updatedAtMs: numberValue(source.updatedAtMs ?? source.updated_at_ms),
    };
}

function normalizeRule(raw: unknown): LevelRuleDto {
    const source = asRecord(raw);
    const displayConfig = source.displayConfigJson ?? source.display_config_json;
    const displayConfigObject = parseDisplayConfig(displayConfig);

    return {
        createdAtMs: numberValue(source.createdAtMs ?? source.created_at_ms),
        displayConfigJson: jsonString(displayConfig),
        level: numberValue(source.level),
        avatarFrameResourceId: numberValue(
            source.avatarFrameResourceId ??
                source.avatar_frame_resource_id ??
                displayConfigObject.avatarFrameResourceId ??
                displayConfigObject.avatar_frame_resource_id,
        ),
        longBadgeResourceId: numberValue(
            source.longBadgeResourceId ??
                source.long_badge_resource_id ??
                displayConfigObject.longBadgeResourceId ??
                displayConfigObject.long_badge_resource_id,
        ),
        name: stringValue(source.name),
        requiredValue: numberValue(source.requiredValue ?? source.required_value),
        rewardResourceGroupId: numberValue(source.rewardResourceGroupId ?? source.reward_resource_group_id),
        shortBadgeResourceId: numberValue(
            source.shortBadgeResourceId ??
                source.short_badge_resource_id ??
                displayConfigObject.shortBadgeResourceId ??
                displayConfigObject.short_badge_resource_id,
        ),
        sortOrder: numberValue(source.sortOrder ?? source.sort_order),
        status: stringValue(source.status),
        track: stringValue(source.track) as LevelTrackCode,
        updatedAtMs: numberValue(source.updatedAtMs ?? source.updated_at_ms),
    };
}

function normalizeTier(raw: unknown): LevelTierDto {
    const source = asRecord(raw);
    return {
        createdAtMs: numberValue(source.createdAtMs ?? source.created_at_ms),
        displayAvatarFrameResourceId: numberValue(
            source.displayAvatarFrameResourceId ?? source.display_avatar_frame_resource_id,
        ),
        displayBadgeResourceId: numberValue(source.displayBadgeResourceId ?? source.display_badge_resource_id),
        displayConfigJson: jsonString(source.displayConfigJson ?? source.display_config_json),
        maxLevel: numberValue(source.maxLevel ?? source.max_level),
        minLevel: numberValue(source.minLevel ?? source.min_level),
        name: stringValue(source.name),
        rewardResourceGroupId: numberValue(source.rewardResourceGroupId ?? source.reward_resource_group_id),
        status: stringValue(source.status),
        tierId: numberValue(source.tierId ?? source.tier_id),
        track: stringValue(source.track) as LevelTrackCode,
        updatedAtMs: numberValue(source.updatedAtMs ?? source.updated_at_ms),
    };
}

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

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

function numberValue(value: unknown): number {
    if (value === undefined || value === null || value === "") {
        return 0;
    }
    const numeric = Number(value);
    return Number.isFinite(numeric) ? numeric : 0;
}

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

function jsonString(value: unknown): string {
    if (value === undefined || value === null || value === "") {
        return "";
    }
    if (typeof value === "string") {
        return value;
    }
    return JSON.stringify(value);
}

function parseDisplayConfig(value: unknown): AnyRecord {
    const raw = jsonString(value).trim();
    if (!raw) {
        return {};
    }
    try {
        return asRecord(JSON.parse(raw));
    } catch {
        return {};
    }
}
