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

export type ExternalAdminUserStatus = "active" | "disabled";

export interface ExternalAdminLinkedUserDto extends CoinLedgerUserDto {
    defaultDisplayUserId?: string;
    status?: string;
}

export interface ExternalAdminUserDto {
    appCode?: string;
    createdAtMs?: number;
    createdByAdminId?: EntityId;
    id: EntityId;
    lastLoginAtMs?: number;
    linkedUser: ExternalAdminLinkedUserDto;
    permissions: string[];
    permissionRevision: number;
    status: ExternalAdminUserStatus;
    updatedAtMs?: number;
    username: string;
}

export interface ExternalAdminUserTargetDto extends ExternalAdminLinkedUserDto {
    existingExternalAdminUser?: ExternalAdminUserDto;
}

export interface ExternalAdminPermissionCatalogItemDto {
    capabilities: string[];
    code: string;
    defaultGranted: boolean;
    dependencies: string[];
    group: string;
    label: string;
}

export interface ExternalAdminPermissionCatalogDto {
    items: ExternalAdminPermissionCatalogItemDto[];
    total: number;
}

export interface ExternalAdminUserPermissionsDto {
    accountId: string;
    permissions: string[];
    revision: number;
}

export interface CreateExternalAdminUserPayload {
    password: string;
    permissions?: string[];
    targetUserId: string;
    username: string;
}

export async function listExternalAdminUsers(
    appCode: string,
    query: PageQuery = {},
): Promise<ApiPage<ExternalAdminUserDto>> {
    const endpoint = API_ENDPOINTS.listExternalAdminUsers;
    const data = await apiRequest<RawPage<RawRecord>>(apiEndpointPath(API_OPERATIONS.listExternalAdminUsers), {
        headers: appScopeHeaders(appCode),
        method: endpoint.method,
        query,
    });
    return normalizePage(data, query);
}

export async function lookupExternalAdminUserTarget(
    appCode: string,
    displayUserId: string,
): Promise<ExternalAdminUserTargetDto> {
    const endpoint = API_ENDPOINTS.lookupExternalAdminUserTarget;
    const data = await apiRequest<RawRecord>(apiEndpointPath(API_OPERATIONS.lookupExternalAdminUserTarget), {
        headers: appScopeHeaders(appCode),
        method: endpoint.method,
        query: { display_user_id: displayUserId },
    });
    return normalizeTarget(data);
}

export async function listExternalAdminPermissionCatalog(
    appCode: string,
): Promise<ExternalAdminPermissionCatalogDto> {
    const endpoint = API_ENDPOINTS.listExternalAdminPermissionCatalog;
    const data = await apiRequest<RawRecord>(apiEndpointPath(API_OPERATIONS.listExternalAdminPermissionCatalog), {
        headers: appScopeHeaders(appCode),
        method: endpoint.method,
    });
    return normalizePermissionCatalog(data);
}

export async function getExternalAdminUserPermissions(
    appCode: string,
    id: EntityId,
): Promise<ExternalAdminUserPermissionsDto> {
    const endpoint = API_ENDPOINTS.getExternalAdminUserPermissions;
    const data = await apiRequest<RawRecord>(
        apiEndpointPath(API_OPERATIONS.getExternalAdminUserPermissions, { id }),
        {
            headers: appScopeHeaders(appCode),
            method: endpoint.method,
        },
    );
    return normalizeUserPermissions(data);
}

export async function createExternalAdminUser(
    appCode: string,
    payload: CreateExternalAdminUserPayload,
): Promise<ExternalAdminUserDto> {
    const endpoint = API_ENDPOINTS.createExternalAdminUser;
    const data = await apiRequest<RawRecord, CreateExternalAdminUserPayload>(
        apiEndpointPath(API_OPERATIONS.createExternalAdminUser),
        {
            body: payload,
            headers: appScopeHeaders(appCode),
            method: endpoint.method,
        },
    );
    return normalizeExternalAdminUser(data);
}

export async function updateExternalAdminUserStatus(
    appCode: string,
    id: EntityId,
    status: ExternalAdminUserStatus,
): Promise<ExternalAdminUserDto> {
    const endpoint = API_ENDPOINTS.updateExternalAdminUserStatus;
    const data = await apiRequest<RawRecord, { status: ExternalAdminUserStatus }>(
        apiEndpointPath(API_OPERATIONS.updateExternalAdminUserStatus, { id }),
        {
            body: { status },
            headers: appScopeHeaders(appCode),
            method: endpoint.method,
        },
    );
    return normalizeExternalAdminUser(data);
}

export async function resetExternalAdminUserPassword(
    appCode: string,
    id: EntityId,
    password: string,
): Promise<ExternalAdminUserDto> {
    const endpoint = API_ENDPOINTS.resetExternalAdminUserPassword;
    const data = await apiRequest<RawRecord, { password: string }>(
        apiEndpointPath(API_OPERATIONS.resetExternalAdminUserPassword, { id }),
        {
            body: { password },
            headers: appScopeHeaders(appCode),
            method: endpoint.method,
        },
    );
    return normalizeExternalAdminUser(data);
}

export async function updateExternalAdminUserPermissions(
    appCode: string,
    id: EntityId,
    permissions: string[],
    expectedRevision: number,
): Promise<ExternalAdminUserDto> {
    const endpoint = API_ENDPOINTS.updateExternalAdminUserPermissions;
    const data = await apiRequest<RawRecord, { expectedRevision: number; permissions: string[] }>(
        apiEndpointPath(API_OPERATIONS.updateExternalAdminUserPermissions, { id }),
        {
            body: { expectedRevision, permissions },
            headers: appScopeHeaders(appCode),
            method: endpoint.method,
        },
    );
    return normalizeExternalAdminUser(data);
}

function appScopeHeaders(appCode: string) {
    // 外管账号是强 App 隔离数据；显式固定请求头，避免切换 App 后全局请求上下文把写操作送到另一租户。
    return { "X-App-Code": String(appCode || "").trim().toLowerCase() };
}

type RawRecord = Record<string, unknown>;

interface RawPage<TItem> {
    items?: TItem[];
    page?: number;
    page_size?: number;
    pageSize?: number;
    total?: number;
}

function normalizePage(data: RawPage<RawRecord>, query: PageQuery): ApiPage<ExternalAdminUserDto> {
    return {
        items: (Array.isArray(data?.items) ? data.items : []).map(normalizeExternalAdminUser),
        page: numberValue(data?.page, Number(query.page || 1)),
        pageSize: numberValue(data?.pageSize ?? data?.page_size, Number(query.page_size || 50)),
        total: numberValue(data?.total),
    };
}

function normalizeExternalAdminUser(raw: RawRecord): ExternalAdminUserDto {
    const item = asRecord(raw) || {};
    const linkedUser = normalizeUser(
        asRecord(item.linkedUser) ||
            asRecord(item.linked_user) ||
            asRecord(item.user) ||
            asRecord(item.targetUser) ||
            asRecord(item.target_user) ||
            item,
    );
    const status = stringValue(item.status).toLowerCase();
    return {
        appCode: stringValue(item.appCode ?? item.app_code),
        createdAtMs: optionalNumber(item.createdAtMs ?? item.created_at_ms),
        createdByAdminId: entityValue(item.createdByAdminId ?? item.created_by_admin_id),
        id: entityValue(item.id ?? item.externalAdminUserId ?? item.external_admin_user_id),
        lastLoginAtMs: optionalNumber(item.lastLoginAtMs ?? item.last_login_at_ms),
        linkedUser,
        permissions: stringArray(item.permissions),
        permissionRevision: numberValue(item.permissionRevision ?? item.permission_revision),
        status: status === "disabled" ? "disabled" : "active",
        updatedAtMs: optionalNumber(item.updatedAtMs ?? item.updated_at_ms),
        username: stringValue(item.username ?? item.account ?? item.accountName ?? item.account_name),
    };
}

function normalizeTarget(raw: RawRecord): ExternalAdminUserTargetDto {
    const item = asRecord(raw) || {};
    const user = normalizeUser(
        asRecord(item.linkedUser) ||
            asRecord(item.linked_user) ||
            asRecord(item.user) ||
            asRecord(item.targetUser) ||
            asRecord(item.target_user) ||
            item,
    );
    const existing =
        asRecord(item.existingExternalAdminUser) ||
        asRecord(item.existing_external_admin_user) ||
        asRecord(item.existingAccount) ||
        asRecord(item.existing_account);
    return {
        ...user,
        existingExternalAdminUser: existing ? normalizeExternalAdminUser(existing) : undefined,
    };
}

function normalizePermissionCatalog(raw: RawRecord): ExternalAdminPermissionCatalogDto {
    const item = asRecord(raw) || {};
    const items = (Array.isArray(item.items) ? item.items : [])
        .map((entry) => {
            const permission = asRecord(entry) || {};
            return {
                capabilities: stringArray(permission.capabilities),
                code: stringValue(permission.code),
                defaultGranted: Boolean(permission.defaultGranted ?? permission.default_granted),
                dependencies: stringArray(permission.dependencies),
                group: stringValue(permission.group),
                label: stringValue(permission.label),
            };
        })
        // 空编码无法用于提交，直接从可选目录剔除，避免 UI 生成不可保存的勾选项。
        .filter((permission) => permission.code);
    return { items, total: numberValue(item.total, items.length) };
}

function normalizeUserPermissions(raw: RawRecord): ExternalAdminUserPermissionsDto {
    const item = asRecord(raw) || {};
    return {
        accountId: stringValue(item.accountId ?? item.account_id),
        permissions: stringArray(item.permissions),
        revision: numberValue(item.revision),
    };
}

function normalizeUser(raw: RawRecord): ExternalAdminLinkedUserDto {
    const user = asRecord(raw) || {};
    return {
        avatar: stringValue(user.avatar),
        defaultDisplayUserId: stringValue(user.defaultDisplayUserId ?? user.default_display_user_id),
        displayUserId: stringValue(
            user.displayUserId ?? user.display_user_id ?? user.defaultDisplayUserId ?? user.default_display_user_id,
        ),
        prettyDisplayUserId: stringValue(user.prettyDisplayUserId ?? user.pretty_display_user_id),
        prettyId: stringValue(user.prettyId ?? user.pretty_id),
        status: stringValue(user.status),
        userId: stringValue(user.userId ?? user.user_id ?? user.targetUserId ?? user.target_user_id),
        username: stringValue(user.username ?? user.name),
    };
}

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

function entityValue(value: unknown): EntityId {
    return typeof value === "number" ? value : stringValue(value);
}

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

function optionalNumber(value: unknown) {
    if (value === undefined || value === null || value === "") {
        return undefined;
    }
    return numberValue(value);
}

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

function stringArray(value: unknown) {
    return Array.isArray(value) ? value.map(stringValue).filter(Boolean) : [];
}
