import { Injectable, inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { of } from 'rxjs';
import { map, exhaustMap, catchError, withLatestFrom, filter } from 'rxjs/operators';
import { SalesDeliveryNoteService } from '../../../services/sales-delivery-note.service';
import { SalesDeliveryNotesActions } from './delivery-notes.actions';
import { selectSalesDeliveryNotesLoaded } from './delivery-notes.reducer';

@Injectable()
export class SalesDeliveryNotesEffects {
  private actions$ = inject(Actions);
  private store = inject(Store);
  private deliveryNoteService = inject(SalesDeliveryNoteService);

  loadDeliveryNotes$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.loadDeliveryNotes),
      withLatestFrom(this.store.select(selectSalesDeliveryNotesLoaded)),
      filter(([action, loaded]) => !!action.force || !loaded),
      exhaustMap(() =>
        this.deliveryNoteService.listAll().pipe(
          map((response) =>
            SalesDeliveryNotesActions.loadDeliveryNotesSuccess({
              deliveryNotes: response.data,
              meta: response.meta,
            })
          ),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.loadDeliveryNotesFailure({
                error: error.error?.message || 'Failed to load delivery notes',
              })
            )
          )
        )
      )
    )
  );

  createDeliveryNote$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.createDeliveryNote),
      exhaustMap(({ data }) =>
        this.deliveryNoteService.create(data).pipe(
          map((response) =>
            SalesDeliveryNotesActions.createDeliveryNoteSuccess({ deliveryNote: response.data })
          ),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.createDeliveryNoteFailure({
                error: error.error?.message || 'Failed to create delivery note',
              })
            )
          )
        )
      )
    )
  );

  updateDeliveryNote$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.updateDeliveryNote),
      exhaustMap(({ id, data }) =>
        this.deliveryNoteService.update(id, data).pipe(
          map((response) =>
            SalesDeliveryNotesActions.updateDeliveryNoteSuccess({ deliveryNote: response.data })
          ),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.updateDeliveryNoteFailure({
                error: error.error?.message || 'Failed to update delivery note',
              })
            )
          )
        )
      )
    )
  );

  deleteDeliveryNote$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.deleteDeliveryNote),
      exhaustMap(({ id }) =>
        this.deliveryNoteService.delete(id).pipe(
          map(() => SalesDeliveryNotesActions.deleteDeliveryNoteSuccess({ id })),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.deleteDeliveryNoteFailure({
                error: error.error?.message || 'Failed to delete delivery note',
              })
            )
          )
        )
      )
    )
  );

  confirmDeliveryNote$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.confirmDeliveryNote),
      exhaustMap(({ id }) =>
        this.deliveryNoteService.confirm(id).pipe(
          map((response) =>
            SalesDeliveryNotesActions.confirmDeliveryNoteSuccess({ deliveryNote: response.data })
          ),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.confirmDeliveryNoteFailure({
                error: error.error?.message || 'Failed to confirm delivery note',
              })
            )
          )
        )
      )
    )
  );

  shipDeliveryNote$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.shipDeliveryNote),
      exhaustMap(({ id, data }) =>
        this.deliveryNoteService.ship(id, data).pipe(
          map((response) =>
            SalesDeliveryNotesActions.shipDeliveryNoteSuccess({ deliveryNote: response.data })
          ),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.shipDeliveryNoteFailure({
                error: error.error?.message || 'Failed to ship delivery note',
              })
            )
          )
        )
      )
    )
  );

  deliverDeliveryNote$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.deliverDeliveryNote),
      exhaustMap(({ id, data }) =>
        this.deliveryNoteService.deliver(id, data).pipe(
          map((response) =>
            SalesDeliveryNotesActions.deliverDeliveryNoteSuccess({ deliveryNote: response.data })
          ),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.deliverDeliveryNoteFailure({
                error: error.error?.message || 'Failed to deliver delivery note',
              })
            )
          )
        )
      )
    )
  );

  cancelDeliveryNote$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SalesDeliveryNotesActions.cancelDeliveryNote),
      exhaustMap(({ id }) =>
        this.deliveryNoteService.cancel(id).pipe(
          map((response) =>
            SalesDeliveryNotesActions.cancelDeliveryNoteSuccess({ deliveryNote: response.data })
          ),
          catchError((error) =>
            of(
              SalesDeliveryNotesActions.cancelDeliveryNoteFailure({
                error: error.error?.message || 'Failed to cancel delivery note',
              })
            )
          )
        )
      )
    )
  );
}
