import isApiError from "@insite/client-framework/Common/isApiError";
import {
    ApiParameter,
    doesNotHaveExpand,
    get,
    HasPagingParameters,
    patch,
    post,
    ServiceResult,
} from "@insite/client-framework/Services/ApiService";
import {
    OrderCollectionModel,
    OrderModel,
    OrderStatusMappingCollectionModel,
    RmaModel,
} from "@insite/client-framework/Types/ApiModels";

export interface GetOrdersApiParameter extends ApiParameter, HasPagingParameters {
    orderNumber?: string;
    poNumber?: string;
    search?: string;
    status?: string[];
    customerSequence?: string;
    fromDate?: string;
    toDate?: string;
    orderTotalOperator?: string;
    orderTotal?: number;
    productErpNumber?: string;
    sort?: string;
    displayName?: string;
    vmiOrdersOnly?: boolean;
    vmiLocationId?: string;
    vmiBinId?: string;
    expand?: ("orderLines" | "vmidetails")[];
    showMyOrders?: boolean;
}

export interface GetOrderApiParameter extends ApiParameter {
    orderNumber: string;
    expand?: ("orderLines" | "shipments" | "vmidetails")[];
    additionalExpands?: string[];
    sTEmail?: string;
    sTPostalCode?: string;
}

export interface GetOrderStatusMappingsApiParameter extends ApiParameter {}

export interface UpdateOrderApiParameter extends ApiParameter {
    order: OrderModel;
}

export interface AddRmaApiParameter extends ApiParameter {
    rmaModel: RmaModel;
}

const ordersUrl = "/api/v1/orders";

export async function getOrders(parameter: GetOrdersApiParameter): Promise<OrderCollectionModel> {
    // can't send empty status array to API
    if (parameter.status && parameter.status.length === 0) {
        delete parameter.status;
    }

    delete (parameter as any).onComplete;
    const orders = await get<OrderCollectionModel>(ordersUrl, parameter);
    orders.orders?.forEach(o => {
        cleanOrder(o, parameter);
    });
    return orders;
}

export function getOrderStatusMappings(parameter: GetOrderStatusMappingsApiParameter) {
    return get<OrderStatusMappingCollectionModel>("/api/v1/orderstatusmappings", parameter);
}

export async function getOrder(parameter: GetOrderApiParameter): Promise<OrderModel> {
    const { orderNumber, ...newParameter } = parameter;

    const order = await get<OrderModel>(`${ordersUrl}/${orderNumber}`, newParameter);
    cleanOrder(order, parameter);
    return order;
}

export async function updateOrder(parameter: UpdateOrderApiParameter) {
    const order = parameter.order;
    const orderNumber = order.erpOrderNumber || order.webOrderNumber;
    const orderModel = await patch<OrderModel>(`${ordersUrl}/${orderNumber}`, order);
    cleanOrder(orderModel);
    return orderModel;
}

export async function addRma(parameter: AddRmaApiParameter): Promise<ServiceResult<RmaModel>> {
    try {
        const rmaModel = await post<RmaModel>(
            `${ordersUrl}/${parameter.rmaModel.orderNumber}/returns`,
            parameter.rmaModel,
        );
        return {
            successful: true,
            result: rmaModel,
        };
    } catch (error) {
        if (isApiError(error) && error.status === 400) {
            return {
                successful: false,
                errorMessage: error.errorJson.message,
            };
        }
        throw error;
    }
}

function cleanOrder(orderModel: OrderModel, parameter?: { expand?: string[]; additionalExpands?: string[] }) {
    orderModel.orderDate = new Date(orderModel.orderDate);
    orderModel.id = cleanOrderFieldNewLine(orderModel.erpOrderNumber) || orderModel.webOrderNumber;
    if (doesNotHaveExpand(parameter, "orderLines")) {
        delete orderModel.orderLines;
    }

    if (!orderModel.shipViaDescription) {
        delete orderModel.shipViaDescription;
    }
}

function cleanOrderFieldNewLine(field: string) {
    // \r\n = CR + LF → Used as a new line character in Windows
    // \r = CR (Carriage Return) → Used as a new line character in Mac OS before X
    // \n = LF (Line Feed) → Used as a new line character in Unix/Mac OS X
    return field.trim().replace(/\r\n/gi, "").replace(/\r/gi, "").replace(/\n/gi, "");
}
