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

export interface AchievementConditionDto {
    achievementId?: string;
    conditionId?: string;
    dimensionFilterJson?: string;
    metricType: string;
    targetUnit?: string;
    targetValue: number;
    version?: number;
}

export interface AchievementDefinitionDto {
    achievementId: string;
    achievementType: string;
    autoPinPolicy?: string;
    collectionId?: string;
    collectionType: string;
    conditions: AchievementConditionDto[];
    createdAtMs?: number;
    createdByAdminId?: number;
    description?: string;
    displayConfigJson?: string;
    effectiveFromMs?: number;
    effectiveToMs?: number;
    honorVisibility?: boolean;
    primaryBadgeResourceId?: number;
    rewardResourceGroupId?: number;
    sortOrder?: number;
    status: string;
    title: string;
    updatedAtMs?: number;
    updatedByAdminId?: number;
    version?: number;
}

export interface AchievementConditionPayload {
    dimension_filter_json: string;
    metric_type: string;
    target_unit: string;
    target_value: number;
}

export interface AchievementDefinitionPayload {
    achievement_type: string;
    auto_pin_policy: string;
    collection_id: string;
    collection_type: string;
    conditions: AchievementConditionPayload[];
    description: string;
    display_config_json: string;
    effective_from_ms: number;
    effective_to_ms: number;
    honor_visibility: boolean;
    primary_badge_resource_id: number;
    reward_resource_group_id: number;
    sort_order: number;
    status: string;
    title: string;
}

type AnyRecord = Record<string, unknown>;

export function listAchievementDefinitions(query: PageQuery = {}): Promise<ApiPage<AchievementDefinitionDto>> {
    const endpoint = API_ENDPOINTS.listAchievementDefinitions;
    return apiRequest<ApiPage<unknown>>(apiEndpointPath(API_OPERATIONS.listAchievementDefinitions), {
        method: endpoint.method,
        query,
    }).then(normalizeAchievementPage);
}

export function createAchievementDefinition(payload: AchievementDefinitionPayload): Promise<AchievementDefinitionDto> {
    const endpoint = API_ENDPOINTS.createAchievementDefinition;
    return apiRequest<unknown, AchievementDefinitionPayload>(
        apiEndpointPath(API_OPERATIONS.createAchievementDefinition),
        {
            body: payload,
            method: endpoint.method,
        },
    ).then(normalizeAchievement);
}

export function updateAchievementDefinition(
    achievementId: EntityId,
    payload: AchievementDefinitionPayload,
): Promise<AchievementDefinitionDto> {
    const endpoint = API_ENDPOINTS.updateAchievementDefinition;
    return apiRequest<unknown, AchievementDefinitionPayload>(
        apiEndpointPath(API_OPERATIONS.updateAchievementDefinition, { achievement_id: achievementId }),
        {
            body: payload,
            method: endpoint.method,
        },
    ).then(normalizeAchievement);
}

export function deleteAchievementDefinition(achievementId: EntityId): Promise<AchievementDefinitionDto> {
    const endpoint = API_ENDPOINTS.deleteAchievementDefinition;
    return apiRequest<unknown>(
        apiEndpointPath(API_OPERATIONS.deleteAchievementDefinition, { achievement_id: achievementId }),
        {
            method: endpoint.method,
        },
    ).then(normalizeAchievement);
}

function normalizeAchievementPage(page: ApiPage<unknown>): ApiPage<AchievementDefinitionDto> {
    return {
        ...page,
        items: (page.items || []).map(normalizeAchievement),
    };
}

function normalizeAchievement(raw: unknown): AchievementDefinitionDto {
    const source = asRecord(raw);
    return {
        achievementId: stringValue(source.achievementId ?? source.achievement_id),
        achievementType: stringValue(source.achievementType ?? source.achievement_type),
        autoPinPolicy: stringValue(source.autoPinPolicy ?? source.auto_pin_policy),
        collectionId: stringValue(source.collectionId ?? source.collection_id),
        collectionType: stringValue(source.collectionType ?? source.collection_type),
        conditions: arrayValue(source.conditions).map(normalizeCondition),
        createdAtMs: numberValue(source.createdAtMs ?? source.created_at_ms),
        createdByAdminId: numberValue(source.createdByAdminId ?? source.created_by_admin_id),
        description: stringValue(source.description),
        displayConfigJson: jsonString(source.displayConfigJson ?? source.display_config_json),
        effectiveFromMs: numberValue(source.effectiveFromMs ?? source.effective_from_ms),
        effectiveToMs: numberValue(source.effectiveToMs ?? source.effective_to_ms),
        honorVisibility: booleanValue(source.honorVisibility ?? source.honor_visibility),
        primaryBadgeResourceId: numberValue(source.primaryBadgeResourceId ?? source.primary_badge_resource_id),
        rewardResourceGroupId: numberValue(source.rewardResourceGroupId ?? source.reward_resource_group_id),
        sortOrder: numberValue(source.sortOrder ?? source.sort_order),
        status: stringValue(source.status),
        title: stringValue(source.title),
        updatedAtMs: numberValue(source.updatedAtMs ?? source.updated_at_ms),
        updatedByAdminId: numberValue(source.updatedByAdminId ?? source.updated_by_admin_id),
        version: numberValue(source.version),
    };
}

function normalizeCondition(raw: unknown): AchievementConditionDto {
    const source = asRecord(raw);
    return {
        achievementId: stringValue(source.achievementId ?? source.achievement_id),
        conditionId: stringValue(source.conditionId ?? source.condition_id),
        dimensionFilterJson: jsonString(source.dimensionFilterJson ?? source.dimension_filter_json),
        metricType: stringValue(source.metricType ?? source.metric_type),
        targetUnit: stringValue(source.targetUnit ?? source.target_unit),
        targetValue: numberValue(source.targetValue ?? source.target_value),
        version: numberValue(source.version),
    };
}

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 booleanValue(value: unknown): boolean {
    return value === true || value === "true" || value === 1 || value === "1";
}

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);
}
