import { inject, Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { Router } from '@angular/router';

import { Action, Selector, State, StateContext, Store } from '@ngxs/store';
import { tap } from 'rxjs';

import { ClearCartAction } from '../action/cart.action';
import {
  CheckoutAction,
  DownloadInvoiceAction,
  GetOrdersAction,
  OrderTrackingAction,
  PlaceOrderAction,
  RePaymentAction,
  ViewOrderAction,
} from '../action/order.action';
import { IOrder, IOrderCheckout } from '../interface/order.interface';
import { NotificationService } from '../services/notification.service';
import { OrderService } from '../services/order.service';

export class OrderStateModel {
  order = {
    data: [] as IOrder[],
    total: 0,
  };
  selectedOrder: IOrder | null;
  checkout: IOrderCheckout | null;
}

@State<OrderStateModel>({
  name: 'order',
  defaults: {
    order: {
      data: [],
      total: 0,
    },
    selectedOrder: null,
    checkout: null,
  },
})
@Injectable()
export class OrderState {
  private router = inject(Router);
  private notificationService = inject(NotificationService);
  private orderService = inject(OrderService);
  private store = inject(Store);

  constructor(@Inject(PLATFORM_ID) private platformId: Object) {}

  @Selector()
  static order(state: OrderStateModel) {
    return state.order;
  }

  @Selector()
  static selectedOrder(state: OrderStateModel) {
    return state.selectedOrder;
  }

  @Selector()
  static checkout(state: OrderStateModel) {
    return state.checkout;
  }

  @Action(GetOrdersAction)
  getOrders(ctx: StateContext<OrderStateModel>, action: GetOrdersAction) {
    return this.orderService.getOrders(action?.payload).pipe(
      tap({
        next: result => {
          ctx.patchState({
            order: {
              data: result.data,
              total: result?.total ? result?.total : result.data?.length,
            },
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(ViewOrderAction)
  viewOrder(ctx: StateContext<OrderStateModel>, { id }: ViewOrderAction) {
    this.orderService.skeletonLoader = true;
    return this.orderService.viewOrder(id).pipe(
      tap({
        next: result => {
          const state = ctx.getState();
          ctx.patchState({
            ...state,
            selectedOrder: result,
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
        complete: () => {
          this.orderService.skeletonLoader = false;
        },
      }),
    );
  }

  @Action(CheckoutAction)
  checkout(ctx: StateContext<OrderStateModel>, action: CheckoutAction) {
    return this.orderService.checkout(action?.payload).pipe(
      tap({
        next: result => {
          const state = ctx.getState();
          ctx.patchState({
            ...state,
            checkout: result,
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(PlaceOrderAction)
  placeOrder(ctx: StateContext<OrderStateModel>, action: PlaceOrderAction) {
    return this.orderService.placeOrder(action?.payload).pipe(
      tap({
        next: result => {
          if (
            (action.payload.payment_method == 'cod' ||
              action.payload.payment_method == 'bank_transfer') &&
            !result.is_guest
          ) {
            void this.router.navigateByUrl(`/account/order/details/${result.order_number}`);
          } else if (
            (action.payload.payment_method == 'cod' ||
              action.payload.payment_method == 'bank_transfer') &&
            result.is_guest
          ) {
            void this.router.navigate(['order/details'], {
              queryParams: {
                order_number: result.order_number,
                email_or_phone: action?.payload.email,
              },
            });
          } else {
            window.open(result.url, '_self');
          }
          this.store.dispatch(new ClearCartAction());
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(RePaymentAction)
  rePayment(ctx: StateContext<OrderStateModel>, action: RePaymentAction) {
    return this.orderService.rePayment(action.payload).pipe(
      tap({
        next: result => {
          if (
            (action.payload.payment_method == 'cod' ||
              action.payload.payment_method == 'bank_transfer') &&
            !result.is_guest
          ) {
            void this.router.navigateByUrl(`/account/order/details/${result.order_number}`);
          } else if (
            (action.payload.payment_method == 'cod' ||
              action.payload.payment_method == 'bank_transfer') &&
            result.is_guest
          ) {
            void this.router.navigate(['order/details'], {
              queryParams: { order_number: result.order_number, email_or_phone: result.email },
            });
          } else {
            window.open(result.url, '_self');
          }
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(OrderTrackingAction)
  orderTracking(ctx: StateContext<OrderStateModel>, action: OrderTrackingAction) {
    this.notificationService.notification = false;
    return this.orderService.orderTracking(action.payload).pipe(
      tap({
        next: result => {
          const state = ctx.getState();
          ctx.patchState({
            ...state,
            selectedOrder: result,
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(DownloadInvoiceAction)
  downloadInvoice(ctx: StateContext<OrderStateModel>, action: DownloadInvoiceAction) {
    return this.orderService.downloadInvoice(action.payload).pipe(
      tap({
        next: result => {
          const blob = new Blob([result], { type: 'pdf' });
          const url = window.URL.createObjectURL(blob);
          const link = document.createElement('a');
          link.href = url;
          link.download = `invoice-${action.payload['order_number']}.pdf`;
          link.click();
          window.URL.revokeObjectURL(url);
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }
}
