import { Maybe } from '@/core';
// import { ICustomerResponse } from '@/modules/customers/models';
import { ToastService } from '@/core/services/toast.service';
import { IGoodCategoryResponse, IGoodResponse } from '@/domains/pos/models/good.io';
import { CustomerType } from '@/shared/localEnum/constants/customerTypes';
import { createUUID, JALALI_DATE_FORMATS, nowJalali } from '@/utils';
import { computed, inject, Injectable, signal } from '@angular/core';
import { catchError, finalize, firstValueFrom, map, throwError } from 'rxjs';
import { ICustomer, IPayment, IPosOrderRequest, IPosOrderResponse } from '../models';
import { IPosInOrderGood, IPosOrderItem } from '../models/types';
import { PosService } from '../services/main.service';

export type TViewType = 'list' | 'grid';
const FAVORITE_CATEGORY_ID = 'favorite';

interface IPosLandingState {
  getGoodsLoading: boolean;
  goods: Maybe<IGoodResponse[]>;
  getGoodCategoriesLoading: boolean;
  goodCategories: Maybe<IGoodCategoryResponse[]>;
  activeGoodCategory: Maybe<string>;
  inOrderGoods: IPosInOrderGood[];
  viewType: TViewType;
  searchQuery: string;
  customerDetails: {
    customer_id?: string;
    info?: ICustomer;
    type: CustomerType;
  };
  invoiceDate: string;
  orderNote?: string;
  payments: IPayment;
  submitOrderLoading: boolean;
}

export const INITIAL_POS_STATE: IPosLandingState = {
  getGoodsLoading: true,
  goods: null,
  getGoodCategoriesLoading: true,
  goodCategories: null,
  activeGoodCategory: null,
  inOrderGoods: [],
  viewType: 'grid',
  searchQuery: '',
  customerDetails: {
    type: CustomerType.UNKNOWN,
  },
  invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC_WITH_FULL_TIME),
  payments: {
    cash: 0,
    set_off: 0,
    terminals: [],
  },
  submitOrderLoading: false,
};

@Injectable({ providedIn: 'any' })
export class PosLandingStore {
  private readonly service = inject(PosService);
  private readonly toastServices = inject(ToastService);

  private state$ = signal<IPosLandingState>({ ...INITIAL_POS_STATE });

  readonly goods = computed(() => this.state$().goods);

  readonly getGoodsLoading = computed(() => this.state$().getGoodsLoading);
  readonly inOrderGoods = computed(() => this.state$().inOrderGoods);
  readonly goodCategories = computed(() => this.state$().goodCategories);
  readonly getGoodCategoriesLoading = computed(() => this.state$().getGoodCategoriesLoading);
  readonly activeGoodCategory = computed(() => this.state$().activeGoodCategory);
  readonly viewType = computed(() => this.state$().viewType);
  readonly searchQuery = computed(() => this.state$().searchQuery);
  readonly submitOrderLoading = computed(() => this.state$().submitOrderLoading);
  readonly activatedCategoryGoods = computed(() => {
    if (!this.activeGoodCategory()) {
      return this.state$().goods;
    }
    if (this.activeGoodCategory() === FAVORITE_CATEGORY_ID) {
      return this.state$().goods?.filter((good) => good.is_favorite);
    }
    return this.state$().goods?.filter((s) => s.category.id === this.state$().activeGoodCategory);
  });
  readonly filteredGoods = computed(() =>
    this.activatedCategoryGoods()?.filter((good) => good.name.includes(this.state$().searchQuery)),
  );

  readonly customer = computed(() => this.state$().customerDetails);
  readonly invoiceDate = computed(() => this.state$().invoiceDate);
  readonly payments = computed(() => this.state$().payments);

  readonly orderPricingInfo = computed(() => {
    let totalAmount = 0;
    let taxAmount = 0;
    let totalBaseAmount = 0;
    let discountAmount = 0;

    this.inOrderGoods().forEach((inOrderGood) => {
      totalBaseAmount += parseInt(inOrderGood.base_total_amount + '') || 0;
      totalAmount += parseInt(inOrderGood.total_amount + '') || 0;
      taxAmount += parseInt(inOrderGood.tax_amount + '') || 0;
      discountAmount += parseInt(inOrderGood.discount_amount + '') || 0;
    });

    return {
      totalItems: this.inOrderGoods().length,
      totalBaseAmount,
      totalAmount,
      taxAmount,
      discountAmount,
      payableAmount: totalAmount + taxAmount,
    };
  });

  setState(partial: Partial<IPosLandingState>) {
    this.state$.set({ ...this.state$(), ...partial });
  }

  reset() {
    this.state$.set({ ...INITIAL_POS_STATE });
  }

  async initial() {
    await Promise.all([this.getGoods(), this.getGoodCategories()]);

    this.prepareGoodCategories();
  }

  fillInitial(data: Partial<IPosLandingState>) {
    this.state$.set({ ...INITIAL_POS_STATE, ...data });
  }

  private async getGoods() {
    this.setState({ getGoodsLoading: true });
    try {
      const res = await firstValueFrom(this.service.getGoods(this.state$().searchQuery));
      this.setState({ goods: res.data, getGoodsLoading: false });
    } catch {
      this.setState({ getGoodsLoading: false });
    }
  }

  private async getGoodCategories() {
    this.setState({ getGoodCategoriesLoading: true });
    try {
      const res = await firstValueFrom(this.service.getGoodCategories());

      this.setState({
        goodCategories: res.data,
        getGoodCategoriesLoading: false,
      });
    } catch {
      this.setState({ getGoodCategoriesLoading: false });
    }
  }

  changeActiveCategory(categoryId: string) {
    this.setState({ activeGoodCategory: categoryId });
  }

  editInOrderGoods(inOrderGood: IPosInOrderGood) {
    this.setState({
      inOrderGoods: [...this.inOrderGoods()].map((orderItem) => {
        if (inOrderGood.id === orderItem.id) {
          return inOrderGood;
        }
        return orderItem;
      }),
    });
  }
  addToInOrderGoods(goodId: string, payload: IPosOrderItem) {
    const good = this.state$().goods?.find((s) => s.id === goodId);

    if (!good) return;

    this.setState({
      inOrderGoods: [
        ...this.inOrderGoods(),
        {
          id: createUUID(),
          good,
          ...payload,
        },
      ],
    });
  }

  removeFromInOrderGoods(orderItemId: string) {
    this.setState({
      inOrderGoods: this.state$().inOrderGoods.filter((p) => p.id !== orderItemId),
    });
  }

  updateViewType(viewType: TViewType) {
    this.setState({ viewType });
  }
  updateSearchQuery(searchQuery: string) {
    this.setState({ searchQuery });
  }

  toggleGoodFavorite(goodId: string, newState: boolean) {
    const updatedGoods = this.state$().goods?.map((good) => {
      if (good.id === goodId) {
        return { ...good, is_favorite: newState };
      }
      return good;
    });
    this.setState({ goods: updatedGoods || this.state$().goods });
    this.prepareGoodCategories();
  }

  private prepareGoodCategories() {
    const rawCategories =
      this.goodCategories()?.filter(({ id }) => id !== '' && id !== FAVORITE_CATEGORY_ID) || [];
    const favoriteGoodsCount = this.goods()?.filter((good) => good.is_favorite).length || 0;
    const goodsCount = this.goods()?.length || 0;
    const preparedGoodCategories = rawCategories;

    if (favoriteGoodsCount > 0) {
      preparedGoodCategories.unshift({
        id: FAVORITE_CATEGORY_ID,
        name: 'علاقه‌مندی‌ها',
        goods_count: favoriteGoodsCount,
      });
    }
    preparedGoodCategories.unshift({
      id: '',
      name: 'همه',
      goods_count: goodsCount,
    });

    this.setState({
      goodCategories: preparedGoodCategories,
    });

    if (!this.activeGoodCategory()) {
      this.setState({ activeGoodCategory: '' });
    }
  }

  filterGoods() {}

  resetInOrderGoods() {
    this.setState({ inOrderGoods: [] });
  }

  setCustomer(customer: { customer_id?: string; info?: ICustomer; type: CustomerType }) {
    this.setState({ customerDetails: customer });
  }

  setPayment(payments: IPayment) {
    this.setState({ payments });
  }

  submitOrder() {
    this.setState({ submitOrderLoading: true });
    const orderPayload: IPosOrderRequest = {
      customer_id: this.customer().customer_id,
      customer_type: this.customer().type,
      customer: this.customer().info,
      items: this.inOrderGoods().map(({ good, ...rest }) => ({
        ...rest,
        good_id: good.id,
        measure_unit: good.measure_unit,
      })),
      invoice_date: new Date().toISOString(),
      payments: this.payments(),
      total_amount: this.orderPricingInfo().totalAmount,
    };

    this.toastServices.info({
      text: `payment submitted: ${this.payments().terminals[0]?.customer_card_no || ''}`,
    });

    let res: Maybe<IPosOrderResponse> = null;

    return this.service.submitOrder(orderPayload).pipe(
      finalize(() => {
        this.setState({ submitOrderLoading: false });
      }),
      catchError((error) => throwError(() => error)),

      map((_res) => {
        if (_res) {
          this.setState({
            inOrderGoods: [],
            customerDetails: {
              type: CustomerType.UNKNOWN,
            },
            invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC),
            payments: {
              cash: 0,
              set_off: 0,
              terminals: [],
            },
            orderNote: '',
          });
        }

        return _res;
      }),
    );
  }
}
