import { Injectable, inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { of } from 'rxjs';
import { exhaustMap, map, catchError, withLatestFrom, filter } from 'rxjs/operators';
import { PurchaseOrderService } from '../../../services/purchase-order.service';
import { PurchaseOrdersActions } from './orders.actions';
import { selectPurchaseOrdersLoaded } from './orders.reducer';

@Injectable()
export class PurchaseOrdersEffects {
  private actions$ = inject(Actions);
  private store = inject(Store);
  private service = inject(PurchaseOrderService);

  loadOrders$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.loadOrders),
      withLatestFrom(this.store.select(selectPurchaseOrdersLoaded)),
      filter(([action, loaded]) => !loaded || action.force === true),
      exhaustMap(() =>
        this.service.listAll().pipe(
          map((res) =>
            PurchaseOrdersActions.loadOrdersSuccess({ orders: res.data, meta: res.meta })
          ),
          catchError((error) =>
            of(
              PurchaseOrdersActions.loadOrdersFailure({
                error: error.error?.message || 'Failed to load purchase orders',
              })
            )
          )
        )
      )
    )
  );

  loadOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.loadOrder),
      exhaustMap(({ id }) =>
        this.service.getById(id).pipe(
          map((res) => PurchaseOrdersActions.loadOrderSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.loadOrderFailure({
                error: error.error?.message || 'Failed to load purchase order',
              })
            )
          )
        )
      )
    )
  );

  createOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.createOrder),
      exhaustMap(({ data }) =>
        this.service.create(data).pipe(
          map((res) => PurchaseOrdersActions.createOrderSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.createOrderFailure({
                error: error.error?.message || 'Failed to create purchase order',
              })
            )
          )
        )
      )
    )
  );

  updateOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.updateOrder),
      exhaustMap(({ id, data }) =>
        this.service.update(id, data).pipe(
          map((res) => PurchaseOrdersActions.updateOrderSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.updateOrderFailure({
                error: error.error?.message || 'Failed to update purchase order',
              })
            )
          )
        )
      )
    )
  );

  deleteOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.deleteOrder),
      exhaustMap(({ id }) =>
        this.service.delete(id).pipe(
          map(() => PurchaseOrdersActions.deleteOrderSuccess({ id })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.deleteOrderFailure({
                error: error.error?.message || 'Failed to delete purchase order',
              })
            )
          )
        )
      )
    )
  );

  submitApproval$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.submitOrderApproval),
      exhaustMap(({ id }) =>
        this.service.submitApproval(id).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to submit for approval',
              })
            )
          )
        )
      )
    )
  );

  approveOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.approveOrder),
      exhaustMap(({ id }) =>
        this.service.approve(id).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to approve order',
              })
            )
          )
        )
      )
    )
  );

  rejectOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.rejectOrder),
      exhaustMap(({ id, data }) =>
        this.service.reject(id, data).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to reject order',
              })
            )
          )
        )
      )
    )
  );

  confirmOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.confirmOrder),
      exhaustMap(({ id }) =>
        this.service.confirm(id).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to confirm order',
              })
            )
          )
        )
      )
    )
  );

  createGrn$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.createOrderGrn),
      exhaustMap(({ id, data }) =>
        this.service.createGrn(id, data || {}).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to create GRN',
              })
            )
          )
        )
      )
    )
  );

  createBill$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.createOrderBill),
      exhaustMap(({ id, data }) =>
        this.service.createBill(id, data || {}).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to create bill',
              })
            )
          )
        )
      )
    )
  );

  cancelOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.cancelOrder),
      exhaustMap(({ id }) =>
        this.service.cancel(id).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to cancel order',
              })
            )
          )
        )
      )
    )
  );

  closeOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.closeOrder),
      exhaustMap(({ id }) =>
        this.service.close(id).pipe(
          map((res) => PurchaseOrdersActions.statusChangeSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to close order',
              })
            )
          )
        )
      )
    )
  );

  duplicateOrder$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PurchaseOrdersActions.duplicateOrder),
      exhaustMap(({ id }) =>
        this.service.duplicate(id).pipe(
          map((res) => PurchaseOrdersActions.duplicateOrderSuccess({ order: res.data })),
          catchError((error) =>
            of(
              PurchaseOrdersActions.statusChangeFailure({
                error: error.error?.message || 'Failed to duplicate order',
              })
            )
          )
        )
      )
    )
  );
}
