'use client';

import { isResponseError } from '@/lib/api-helper';
import { InventoryAdjustmentApi } from '@/services/api/inventory';
import {
  CreateInventoryAdjustmentPayload,
  InventoryAdjustment,
} from '@/types/api/inventory/adjustment';
import { useFormik } from 'formik';
import { useRouter } from 'next/navigation';
import { useCallback, useEffect, useMemo, useState } from 'react';
import toast from 'react-hot-toast';
import {
  InventoryAdjustmentFormSchema,
  InventoryAdjustmentFormValues,
} from '@/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema';
import useSWR from 'swr';
import {
  ProductApi,
  ProductCategoryApi,
  WarehouseApi,
} from '@/services/api/master-data';
import Button from '@/components/Button';
import { Icon } from '@iconify/react';
import SelectInput, {
  OptionType,
  useSelect,
} from '@/components/input/SelectInput';
import TextInput from '@/components/input/TextInput';
import { RadioGroup } from '@/components/input/RadioInput';
import TextArea from '@/components/input/TextArea';
import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
import AlertErrorList from '@/components/helper/form/FormErrors';
import { ProductCategory } from '@/types/api/master-data/product-category';
import { Product } from '@/types/api/master-data/product';
import { Warehouse } from '@/types/api/master-data/warehouse';

interface InventoryAdjustmentFormProps {
  type?: 'add' | 'edit' | 'detail';
  initialValues?: InventoryAdjustment;
}

const InventoryAdjustmentForm = ({
  type = 'add',
  initialValues,
}: InventoryAdjustmentFormProps) => {
  // State
  const router = useRouter();
  const [
    InventoryAdjustmentFormErrorMessage,
    setInventoryAdjustmentFormErrorMessage,
  ] = useState('');
  const [disabledProduct, setDisabledProduct] = useState(true);
  const [quantityLabel, setQuantityLabel] = useState('Tambah Stok');

  // Submit Handler
  const createInventoryAdjustmentHandler = useCallback(
    async (payload: CreateInventoryAdjustmentPayload) => {
      const createInventoryAdjustmentRes =
        await InventoryAdjustmentApi.create(payload);

      if (isResponseError(createInventoryAdjustmentRes)) {
        setInventoryAdjustmentFormErrorMessage(
          createInventoryAdjustmentRes.message
        );
        return;
      }

      toast.success(createInventoryAdjustmentRes?.message as string);
      router.push('/inventory/adjustment');
    },
    [router]
  );

  const formikInitialValues = useMemo<
    Partial<InventoryAdjustmentFormValues>
  >(() => {
    return {
      product_id: initialValues?.product_warehouse?.product_id ?? 0,
      warehouse_id: initialValues?.product_warehouse?.warehouse_id ?? 0,
      product_category: undefined,
      product: undefined,
      warehouse: undefined,
      quantity: initialValues?.increase ?? initialValues?.decrease ?? 0,
      transaction_type: undefined,
      note: initialValues?.note ?? '',
    };
  }, [initialValues]);

  // Formik
  const formik = useFormik<InventoryAdjustmentFormValues>({
    enableReinitialize: true,
    initialValues: formikInitialValues as InventoryAdjustmentFormValues,
    validationSchema: InventoryAdjustmentFormSchema,
    onSubmit: async (values) => {
      setInventoryAdjustmentFormErrorMessage('');
      const payload: CreateInventoryAdjustmentPayload = {
        product_id: values.product_id as number,
        warehouse_id: values.warehouse_id as number,
        quantity: values.quantity as number,
        transaction_type: values.transaction_type as string,
        note: values.note,
      };

      switch (type) {
        case 'add':
          await createInventoryAdjustmentHandler(payload);
          break;
      }
    },
  });

  // Fetch Data
  const {
    setInputValue: setProductCategoryInputValue,
    options: productCategoryOptions,
    isLoadingOptions: isLoadingProductCategoryOptions,
    loadMore: loadMoreProductCategories,
  } = useSelect<ProductCategory>(ProductCategoryApi.basePath, 'id', 'name');

  const {
    setInputValue: setProductInputValue,
    options: productOptions,
    isLoadingOptions: isLoadingProductOptions,
    loadMore: loadMoreProducts,
  } = useSelect<Product>(ProductApi.basePath, 'id', 'name', 'search', {
    product_category_id: formik.values.product_category_id
      ? String(formik.values.product_category_id)
      : '',
  });

  const {
    setInputValue: setWarehouseInputValue,
    options: warehouseOptions,
    isLoadingOptions: isLoadingWarehouseOptions,
    loadMore: loadMoreWarehouses,
  } = useSelect<Warehouse>(WarehouseApi.basePath, 'id', 'name');

  // Options Handler
  const productCategoryChangeHandler = (
    val: OptionType | OptionType[] | null
  ) => {
    formik.setFieldTouched('product_category_id', true);
    formik.setFieldValue('product_category_id', (val as OptionType)?.value);

    formik.setFieldValue('product_category', val);

    const disabled = (val as OptionType)?.value == null;
    setDisabledProduct(disabled);
    formik.setFieldValue('product_id', 0);
    formik.setFieldValue('product', null);
    formik.setFieldTouched('product', false);
    formik.setFieldTouched('product_id', false);
  };

  const productChangeHandler = (val: OptionType | OptionType[] | null) => {
    formik.setFieldValue('product', val);

    formik.setFieldTouched('product_id', true);
    formik.setFieldValue('product_id', (val as OptionType)?.value);
  };

  const warehouseChangeHandler = (val: OptionType | OptionType[] | null) => {
    formik.setFieldValue('warehouse', val);

    formik.setFieldTouched('warehouse_id', true);
    formik.setFieldValue('warehouse_id', (val as OptionType)?.value);
  };

  const resetHandler = () => {
    formik.resetForm();
    setQuantityLabel('Tambah Stok');
    productCategoryChangeHandler(null);
    productChangeHandler(null);
    warehouseChangeHandler(null);
  };

  const { setValues: formikSetValues } = formik;

  // Effect
  useEffect(() => {
    if (initialValues?.product_warehouse?.product?.id) {
      setDisabledProduct(false);
      formik.setFieldValue(
        'product_id',
        initialValues.product_warehouse.product.id
      );
      formik.setFieldValue('product', {
        value: initialValues.product_warehouse.product.id,
        label: initialValues.product_warehouse.product.name,
      });
      formik.setFieldValue(
        'warehouse_id',
        initialValues.product_warehouse.warehouse.id
      );
      formik.setFieldValue('warehouse', {
        value: initialValues.product_warehouse.warehouse.id,
        label: initialValues.product_warehouse.warehouse.name,
      });
      formik.setFieldValue(
        'quantity',
        initialValues.product_warehouse.quantity
      );
      formik.setFieldValue('note', initialValues.note);
    }
  }, [formik, initialValues, setQuantityLabel, setDisabledProduct]);
  useEffect(() => {
    formikSetValues(formikInitialValues as InventoryAdjustmentFormValues);
  }, [formikSetValues, formikInitialValues]);

  // Utils Function
  const formatNumber = (value: string) => {
    const numericValue = value.replace(/[^0-9.]/g, '');
    const [integer, decimal] = numericValue.split('.');
    const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return decimal ? `${formattedInteger}.${decimal}` : formattedInteger;
  };

  // ===== Formik Error List =====
  const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik);

  // Render
  return (
    <>
      <section className='w-full max-w-xl'>
        <header className='flex flex-col gap-4'>
          <Button
            href='/inventory/adjustment'
            variant='link'
            className='w-fit p-0 text-primary'
          >
            <Icon icon='uil:arrow-left' width={24} height={24} />
            Kembali
          </Button>

          <h1 className='text-2xl font-bold text-center'>
            {type === 'add' && 'Tambah Penyesuaian Persediaan'}
            {type === 'detail' && 'Detail Penyesuaian Persediaan'}
          </h1>
        </header>

        <form
          onSubmit={handleFormSubmit}
          onReset={formik.handleReset}
          className='w-full mt-8 flex flex-col gap-6'
        >
          <div className='flex flex-col gap-4'>
            {/* Select Input Product Category */}
            <SelectInput
              required
              label='Kategori Produk'
              value={formik.values.product_category as OptionType}
              onChange={productCategoryChangeHandler}
              onInputChange={setProductCategoryInputValue}
              options={productCategoryOptions}
              onMenuScrollToBottom={loadMoreProductCategories}
              isLoading={isLoadingProductCategoryOptions}
              isError={
                formik.touched.product_category &&
                Boolean(formik.errors.product_category)
              }
              errorMessage={formik.errors.product_category as string}
              isDisabled={type === 'detail'}
              isClearable
            />

            {/* Select Input Product */}
            <SelectInput
              required
              label='Produk'
              value={formik.values.product as OptionType}
              onChange={productChangeHandler}
              onInputChange={setProductInputValue}
              options={productOptions}
              onMenuScrollToBottom={loadMoreProducts}
              isLoading={isLoadingProductOptions}
              isError={formik.touched.product && Boolean(formik.errors.product)}
              errorMessage={formik.errors.product as string}
              isDisabled={type === 'detail' || disabledProduct}
              isClearable
            />

            {/* Select Input Warehouse */}
            <SelectInput
              required
              label='Warehouse'
              value={formik.values.warehouse as OptionType}
              onChange={warehouseChangeHandler}
              onInputChange={setWarehouseInputValue}
              options={warehouseOptions}
              onMenuScrollToBottom={loadMoreWarehouses}
              isLoading={isLoadingWarehouseOptions}
              isError={
                formik.touched.warehouse && Boolean(formik.errors.warehouse)
              }
              errorMessage={formik.errors.warehouse as string}
              isDisabled={type === 'detail'}
              isClearable
            />

            {/* Radio Button Flag Stock */}
            <RadioGroup
              name='transaction_type'
              label='Tipe Transaksi'
              options={[
                { label: 'Tambah', value: 'increase' },
                { label: 'Kurang', value: 'decrease' },
              ]}
              value={formik.values.transaction_type}
              onChange={(e) => {
                formik.handleChange(e);
                setQuantityLabel(
                  e.target.value === 'increase' ? 'Tambah Stok' : 'Kurangi Stok'
                );
              }}
              onBlur={formik.handleBlur}
              isError={
                formik.touched.transaction_type &&
                Boolean(formik.errors.transaction_type)
              }
              errorMessage={formik.errors.transaction_type as string}
              color='primary'
              required
              bottomLabel={
                formik.values.transaction_type == undefined
                  ? 'Pilih salah satu tipe transaksi'
                  : undefined
              }
              disabled={type === 'detail'}
            />

            {/* Number Input Stock */}
            <TextInput
              className={{
                wrapper: `${formik.values.transaction_type != undefined ? '' : 'hidden'}`,
              }}
              required
              label={quantityLabel}
              name='quantity'
              type='text'
              value={formatNumber(String(formik.values.quantity))}
              onChange={(e) => {
                const rawValue = e.target.value.replace(/,/g, '');
                const numericValue = parseFloat(rawValue);
                if (!isNaN(numericValue)) {
                  formik.setFieldValue('quantity', numericValue);
                } else {
                  formik.setFieldValue('quantity', 0);
                }
              }}
              onBlur={formik.handleBlur}
              isError={
                formik.touched.quantity && Boolean(formik.errors.quantity)
              }
              errorMessage={formik.errors.quantity as string}
              readOnly={type === 'detail'}
            />

            {/* Text Area Input Reason */}
            <TextArea
              required
              label='Alasan'
              name='note'
              value={formik.values.note as string}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={formik.touched.note && Boolean(formik.errors.note)}
              errorMessage={formik.errors.note as string}
              readOnly={type === 'detail'}
            />
          </div>
          <AlertErrorList formErrorList={formErrorList} onClose={close} />
          <div className='flex flex-row justify-between gap-2 flex-wrap'>
            {type !== 'detail' && (
              <div className='flex flex-row justify-end gap-2'>
                <Button
                  type='button'
                  color='warning'
                  className='px-4'
                  onClick={resetHandler}
                >
                  Reset
                </Button>
                <Button
                  type='submit'
                  color='primary'
                  isLoading={formik.isSubmitting}
                  disabled={formik.isSubmitting}
                  className='px-4'
                >
                  Submit
                </Button>
              </div>
            )}
          </div>
          {InventoryAdjustmentFormErrorMessage && (
            <div role='alert' className='alert alert-error'>
              <Icon
                icon='material-symbols:error-outline'
                width={24}
                height={24}
              />
              <span>{InventoryAdjustmentFormErrorMessage}</span>
            </div>
          )}
        </form>
      </section>
    </>
  );
};

export default InventoryAdjustmentForm;
