import { Client } from '@vulog/aima-client';
import { createPaginableOptionsSchema, PaginableOptions, PaginableResponse } from '@vulog/aima-core';
import { z } from 'zod';

import { Event } from './types';

const EventTypeList = z.enum([
    'USER_ACCOUNT_UPDATE',
    'USER_SUSPENDED',
    'USER_REJECTED',
    'USER_CREATED',
    'USER_APPROVED',
    'USER_INCOMPLETE',
    'USER_ARCHIVED',
    'USER_INACTIVE',
    'USER_RESET_PASSWORD',
    'USER_ROLE_ADD',
    'USER_ROLE_DEL',
    'USER_BOOKING_REQUEST',
    'USER_UPDATE_BOOKING_REQUEST',
    'USER_DELETE_BOOKING_REQUEST',
    'USER_CANCEL_BOOKING_REQUEST',
    'USER_PROMOCODE_REDEEM',
    'USER_SYSTEM_CREDIT_ADD',
    'USER_SYSTEM_CREDIT_CONSUMED',
    'USER_SYSTEM_CREDIT_REMOVED',
    'USER_PRODUCT_CHARGED',
    'USER_TRIP_INVOICE_CREATED',
    'USER_TRIP_INVOICE_UPDATED',
    'USER_PRODUCT_INVOICE_CREATED',
    'USER_PRODUCT_EXPENSE_CREATED',
    'USER_PRODUCT_INVOICE_UPDATED',
    'VEHICLE_ADDED_TO_STATION',
    'VEHICLE_REMOVED_FROM_STATION',
    'VEHICLE_ALLOCATED',
    'VEHICLE_ARCHIVED',
    'VEHICLE_UPDATED',
    'VEHICLE_REMOVE_VUBOX',
    'VEHICLE_ASSIGN_VUBOX',
    'VEHICLE_OUT_OF_SERVICE',
    'VEHICLE_SCHEDULED_OUT_OF_SERVICE',
    'VEHICLE_SCHEDULED_OUT_OF_SERVICE_CANCELED',
    'VEHICLE_UNLOCK',
    'VEHICLE_LOCK',
    'VEHICLE_HELMET_LOCK',
    'VEHICLE_HELMET_UNLOCK',
    'VEHICLE_SPARE_LOCK',
    'VEHICLE_SPARE_UNLOCK',
    'VEHICLE_PILE_LOCK',
    'VEHICLE_PILE_UNLOCK',
    'VEHICLE_SPEED_LIMIT_CHANGED',
    'VEHICLE_WAKE_UP',
    'VEHICLE_WAKE_UP_ACCEL',
    'VEHICLE_WAKE_UP_BLE',
    'VEHICLE_CONNECTIVITY_ONLINE',
    'VEHICLE_CONNECTIVITY_OFFLINE',
    'VEHICLE_CONNECTIVITY_INTERRUPTED',
    'VEHICLE_OUT_OF_COM',
    'VEHICLE_BOOKING_STATUS_CHANGED',
    'VEHICLE_GET_STATUS',
    'VEHICLE_SCHEDULED_REBOOT',
    'VEHICLE_WARNING',
    'VEHICLE_CRUISING_RANGE_LOW',
    'VEHICLE_CRUISING_RANGE_CRITICAL',
    'VEHICLE_ACCEL_ALERT',
    'VEHICLE_SPEED_ALERT',
    'VEHICLE_RECOVERY',
    'VEHICLE_SYNC',
    'VEHICLE_STANDBY',
    'VEHICLE_AUTOCLOSE_ON',
    'VEHICLE_AUTOCLOSE_OFF',
    'VEHICLE_IGNITION_ON',
    'VEHICLE_IGNITION_OFF',
    'VEHICLE_REBOOT',
    'VEHICLE_MOBILIZE',
    'VEHICLE_IMMOBILIZE',
    'VEHICLE_ENABLE',
    'VEHICLE_CLEANLINESS_RESET',
    'VEHICLE_ADD_ZONE',
    'VEHICLE_REMOVE_ZONE',
    'VEHICLE_RELEASE_TRIP',
    'VEHICLE_START_TRIP',
    'VEHICLE_END_TRIP',
    'VEHICLE_EDIT_TRIP',
    'VEHICLE_MANUAL_END_TRIP',
    'VEHICLE_TRACKING_ON',
    'VEHICLE_TRACKING_OFF',
    'VEHICLE_TRIP_TERMINATION',
    'VEHICLE_PAUSE_TRIP',
    'VEHICLE_FORCED_PAUSE_TRIP',
    'VEHICLE_RESUME_TRIP',
    'VEHICLE_EXPERT',
    'VEHICLE_PING',
    'VEHICLE_CANCEL_TRIP',
    'VEHICLE_REMOVE_PRODUCT_TRIP',
    'VEHICLE_BOOK',
    'VEHICLE_ADD_PRODUCT_TRIP',
    'VEHICLE_UPDATE_REASON',
    'VEHICLE_RESET_CLEAN_DATE',
    'VEHICLE_RESET_REDISTRIB_DATE',
    'VEHICLE_RESET_MOVING_DATE',
    'VEHICLE_ANTITHEFT_ON',
    'VEHICLE_ANTITHEFT_OFF',
    'VEHICLE_CHARGING_ACTIVE',
    'VEHICLE_CHARGING_ENDED',
    'VEHICLE_CHARGING_PLUGGED',
    'VEHICLE_CHARGING_UNPLUGGED',
    'VEHICLE_BATTERY_OK',
    'VEHICLE_BATTERY_LOW',
    'VEHICLE_BATTERY_CRITICAL',
    'VEHICLE_DOORS_OPEN',
    'VEHICLE_DOORS_CLOSED',
    'VEHICLE_WINDOWS_OPEN',
    'VEHICLE_WINDOWS_CLOSED',
    'VEHICLE_ALERT',
    'VEHICLE_FATAL',
    'VEHICLE_PRICING_CHANGED',
    'VEHICLE_GROUP_CHANGED',
    'VEHICLE_UPDATE_ODOMETER',
    'VEHICLE_UPDATE_STATUS',
    'VEHICLE_UPDATE_GPS_MANUAL',
    'VEHICLE_UPDATE_GPS_SIM',
    'VEHICLE_RFID_SYNC',
    'VEHICLE_PREAUTH_CONFIRMED',
    'VEHICLE_PREAUTH_REJECTED',
    'VEHICLE_PREAUTH_EXPIRED',
    'VEHICLE_PREAUTH_CANCELLED',
    'USER_PRODUCT_INVOICE_CANCELLED',
    'USER_TRIP_INVOICE_CANCELLED',
    'USER_PRODUCT_INVOICE_REFUSED',
    'USER_TRIP_INVOICE_REFUSED',
    'USER_TRIP_INVOICE_PAID',
    'USER_PRODUCT_INVOICE_PAID',
    'USER_TRIP_INVOICE_REFUNDED',
    'USER_PRODUCT_INVOICE_REFUNDED',
    'USER_PLAN_SUBSCRIBED',
    'USER_PLAN_UNSUBSCRIBED',
    'USER_REFERRAL_CREATED',
    'USER_REFERRAL_CHECKED',
    'USER_REPORT_CREATED',
    'USER_REPORT_UPDATED',
    'USER_DOC_UPDATED',
    'USER_PLAN_RENEWED',
    'USER_BILLING_GROUP_ADDED',
    'USER_BILLING_GROUP_REMOVED',
    'VEHICLE_ADDED_TO_SERVICE',
    'VEHICLE_REMOVED_FROM_SERVICE',
    'USER_PLAN_RENEWAL',
    'USER_PLAN_CANCELED',
    'USER_PLAN_UPDATED',
    'USER_RFIDPINCODE_REQUESTED',
    'VEHICLE_REFILLED',
    'VEHICLE_BLE_AUTH',
    'VEHICLE_FIRMWARE_UPDATE',
    'USER_TRIP_EVENT_MAP_DISPLAY_GDPR',
    'USER_AUTOMATICALLY_REFUNDED',
    'USER_TRIP_CREDIT_REFUNDED',
    'USER_PRODUCT_CREDIT_REFUNDED',
    'USER_CREDIT_REFUNDED',
    'USER_ALL_CREDIT_REFUNDED',
    'USER_PREPAYMENT_SUCCEEDED',
    'USER_PREPAYMENT_FAILED',
    'USER_CREATE_SUBSCRIPTION',
    'USER_UPDATE_SUBSCRIPTION',
]);

export type EventType = z.infer<typeof EventTypeList>;
export type EventFilters = {
    /**
     * Format: yyyy-MM-dd'T'HH:mm:ssZ
     * default now
     */
    startDate?: string;
    /**
     * Format: yyyy-MM-dd'T'HH:mm:ssZ
     * default now plus 2 months
     */
    endDate?: string;
};

export const getEventsByType = async (
    client: Client,
    type: EventType,
    options?: PaginableOptions<EventFilters>
): Promise<PaginableResponse<Event>> => {
    const resultStatus = EventTypeList.safeParse(type);
    if (!resultStatus.success) {
        throw new TypeError('Invalid status', {
            cause: resultStatus.error.issues,
        });
    }
    const date = new Date();
    date.setMilliseconds(0);
    const startDate = date.toISOString().replace('.000Z', 'Z');
    date.setMonth(date.getMonth() + 2);
    const endDate = date.toISOString().replace('.000Z', 'Z');
    const EventFiltersSchema = z.object({
        startDate: z.string().datetime({ offset: false, precision: 0 }).default(startDate),
        endDate: z.string().datetime({ offset: false, precision: 0 }).default(endDate),
    });
    const PaginableOptionsSchema = createPaginableOptionsSchema(EventFiltersSchema).default({});

    const resultOptions = PaginableOptionsSchema.safeParse(options);
    if (!resultOptions.success) {
        throw new TypeError('Invalid options', {
            cause: resultOptions.error.issues,
        });
    }

    const finalOptions = resultOptions.data;

    const searchParams = new URLSearchParams();
    searchParams.append('page', finalOptions.page!.toString());
    searchParams.append('pageSize', finalOptions.pageSize!.toString());

    Object.entries(finalOptions.filters!).forEach(([key, value]) => {
        if (value === undefined) {
            return;
        }
        searchParams.append(key, value as string);
    });

    return client
        .get<
            Event[]
        >(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/events/types/${type}?${searchParams.toString()}`)
        .then(({ data, headers }) => {
            return {
                data,
                page: headers.number,
                pageSize: headers.size,
                total: headers.totalelements,
                totalPages: headers.totalpages,
            };
        });
};

export const getEvents = async (
    client: Client,
    options?: PaginableOptions<EventFilters>
): Promise<PaginableResponse<Event>> => {
    const date = new Date();
    date.setMilliseconds(0);
    const startDate = date.toISOString().replace('.000Z', 'Z');
    date.setMonth(date.getMonth() + 2);
    const endDate = date.toISOString().replace('.000Z', 'Z');
    const EventFiltersSchema = z.object({
        startDate: z.string().datetime({ offset: false, precision: 0 }).default(startDate),
        endDate: z.string().datetime({ offset: false, precision: 0 }).default(endDate),
    });
    const PaginableOptionsSchema = createPaginableOptionsSchema(EventFiltersSchema).default({});

    const resultOptions = PaginableOptionsSchema.safeParse(options);
    if (!resultOptions.success) {
        throw new TypeError('Invalid options', {
            cause: resultOptions.error.issues,
        });
    }

    const finalOptions = resultOptions.data;

    const searchParams = new URLSearchParams();
    searchParams.append('page', finalOptions.page!.toString());
    searchParams.append('pageSize', finalOptions.pageSize!.toString());

    Object.entries(finalOptions.filters!).forEach(([key, value]) => {
        if (value === undefined) {
            return;
        }
        searchParams.append(key, value as string);
    });

    return client
        .get<
            Event[]
        >(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/events/types?${searchParams.toString()}`)
        .then(({ data, headers }) => {
            return {
                data,
                page: headers.number,
                pageSize: headers.size,
                total: headers.totalelements,
                totalPages: headers.totalpages,
            };
        });
};
