import ApiRequest from "@services/Api.Service";
import {
    ClientMergeParams,
    DeleteClientParams,
    FindClientByIdParams,
    OrganizationClientView,
    UpdateClientParams,
} from "@models/Clients.model";
import { ApiVoidResult } from "@core/Models/Api.VoidResult.type";
import * as Yup from "yup";
import {
    CreateRepeatsParams,
    DeleteRepeatsParams,
    FindRepeatsParams,
    IRepeat,
    RepeatView,
    GetPendingRepeatsParams,
    PendingRepeatView,
} from "@core/Models/Repeats.model";
import {
    ClientAccountReport,
    ClientAccountView,
    FindClientAccountsParams,
    GetClientAccountReportParams,
} from "@core/Models/ClientAccounts.model";
import {
    CreateClientAccountMovementParams,
    IClientAccountMovement,
    PaginateClientAccountMovementsParams,
    PaginateClientAccountMovementsResults,
} from "@core/Models/ClientAccountMovements.model";
import { ApiError } from "@core/Models/Server.Error.model";

const schemaRepeatsAdd = Yup.object().shape({
    companyId: Yup.string().required("Debe seleccionar una organización."),
    employeeId: Yup.string().required("Debe seleccionar un profesional."),
    serviceId: Yup.string().required("Debe seleccionar un servicio."),
    clientId: Yup.string().required("Debe seleccionar un cliente."),
    weekDay: Yup.number().required("Debe indicar un día de la semana."),
    startHour: Yup.number().required("Debe indicar una hora de inicio."),
    sessionUser: Yup.string().required("Para crear una organización debe iniciar sesión."),
});

const schemaClientUpdate = Yup.object().shape({
    firstName: Yup.string().required("Debe introducir el nombre del cliente."),
    lastName: Yup.string().required("Debe introducir el apellido del cliente."),
    email: Yup.string().required().email("Debe introducir un E-mail valido."),
    phoneAreaCode: Yup.number()
        .required("Debe introducir el código de área.")
        .typeError("El código de área debe ser un número."),
    phoneNumber: Yup.number()
        .required("Debe introducir el número de teléfono.")
        .typeError("El número de teléfono debe ser un número."),
    sessionUser: Yup.string().required("Para crear una organización debe iniciar sesión."),
});

const schemaClientMerge = Yup.object().shape({
    fromClientId: Yup.string().required(
        "Para fusionar dos clientes es necesario seleccionar el cliente de orgigen."
    ),
    toClientId: Yup.string().required(
        "Para fusionar dos clientes es necesario seleccionar el cliente de destino."
    ),
    sessionUser: Yup.string().required("Para crear una organización debe iniciar sesión."),
});

const schemaAccountMovementAdd = Yup.object().shape({
    clientId: Yup.string().required("Debe seleccionar un cliente."),
    description: Yup.string().required("Debe introducir una descripción para el movimiento."),
    paymentMethod: Yup.string().required("Debe seleccionar un método de pago."),
    type: Yup.string().required("Debe seleccionar un tipo de movimiento."),
    status: Yup.string().required("Debe seleccionar un estado del movimiento."),
    amount: Yup.number()
        .required("Debe introducir el monto del movimiento.")
        .typeError("El monto debe ser un número.")
        .positive("El monto debe ser un número positivo."),

    sessionUser: Yup.string().required("Para cargar un movimiento debe iniciar sesión."),
});

export const findClientById = async (
    data: FindClientByIdParams
): Promise<OrganizationClientView> => {
    return ApiRequest.post<OrganizationClientView>("clients/find-by-id", data);
};

export const updateClient = async (data: UpdateClientParams): Promise<ApiVoidResult> => {
    let yupErrors: Yup.ValidationError = new Yup.ValidationError("");
    const validateData = async () => {
        try {
            await schemaClientUpdate.validate(data, { abortEarly: true });
            return true;
        } catch (error) {
            if (error instanceof Yup.ValidationError) {
                yupErrors = error as Yup.ValidationError;
            }
            return false;
        }
    };

    if ((await validateData()) == false) {
        throw new Error(yupErrors.message);
    }

    return ApiRequest.post<ApiVoidResult>("clients/update", data);
};

export const deleteClient = async (data: DeleteClientParams): Promise<ApiVoidResult> => {
    return ApiRequest.post<ApiVoidResult>("clients/delete", data);
};

export const clientMerge = async (data: ClientMergeParams): Promise<ApiVoidResult> => {
    let yupErrors: Yup.ValidationError = new Yup.ValidationError("");
    const validateData = async () => {
        try {
            await schemaClientMerge.validate(data, { abortEarly: true });
            return true;
        } catch (error) {
            if (error instanceof Yup.ValidationError) {
                yupErrors = error as Yup.ValidationError;
            }
            return false;
        }
    };

    if ((await validateData()) == false) {
        throw new Error(yupErrors.message);
    }

    return ApiRequest.post<ApiVoidResult>("clients/merge", data);
};

export const repeatAdd = async (data: CreateRepeatsParams): Promise<IRepeat> => {
    let yupErrors: Yup.ValidationError = new Yup.ValidationError("");
    const validateData = async () => {
        try {
            await schemaRepeatsAdd.validate(data, { abortEarly: true });
            return true;
        } catch (error) {
            if (error instanceof Yup.ValidationError) {
                yupErrors = error as Yup.ValidationError;
            }
            return false;
        }
    };

    if ((await validateData()) == false) {
        throw new Yup.ValidationError(yupErrors.message);
    }

    return ApiRequest.post<IRepeat>("repeats/create", data);
};

export const getRepeatsByClient = async (data: FindRepeatsParams): Promise<RepeatView[]> => {
    return ApiRequest.post<RepeatView[]>("repeats/repeats-by-client", data);
};

export const deleteRepeat = async (data: DeleteRepeatsParams): Promise<ApiVoidResult> => {
    return ApiRequest.post<ApiVoidResult>("repeats/delete", data);
};

export const getPendingRepeatsCurrentWeek = async (data: GetPendingRepeatsParams): Promise<PendingRepeatView[]> => {
    return ApiRequest.post<PendingRepeatView[]>("repeats/pending-current-week", data);
};

export const getClientAccountView = async (
    data: FindClientAccountsParams
): Promise<ClientAccountView> => {
    return ApiRequest.post<ClientAccountView>("client-accounts/client-view", data);
};

export const addClientAccountMovement = async (
    data: CreateClientAccountMovementParams
): Promise<IClientAccountMovement> => {
    let yupErrors: Yup.ValidationError = new Yup.ValidationError("");
    const validateData = async () => {
        try {
            await schemaAccountMovementAdd.validate(data, {
                abortEarly: true,
            });
            return true;
        } catch (error) {
            if (error instanceof Yup.ValidationError) {
                yupErrors = error as Yup.ValidationError;
            }
            return false;
        }
    };

    if ((await validateData()) == false) {
        throw new ApiError(400, yupErrors.message);
    }

    return ApiRequest.post<IClientAccountMovement>("client-accounts/add-movement", data);
};

export const paginateClientAccountMovements = async (
    data: PaginateClientAccountMovementsParams
): Promise<PaginateClientAccountMovementsResults> => {
    return ApiRequest.post<PaginateClientAccountMovementsResults>(
        "client-accounts/paginate-movements",
        data
    );
};

export const GetClientAccountReport = async (
    data: GetClientAccountReportParams
): Promise<ClientAccountReport> => {
    return ApiRequest.post<ClientAccountReport>("client-accounts/get-account-report", data);
};
