'use client';

import { useCallback, useEffect, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { useFormik } from 'formik';
import { toast } from 'react-hot-toast';

import { Icon } from '@iconify/react';
import Button from '@/components/Button';
import TextInput from '@/components/input/TextInput';
import NumberInput from '@/components/input/NumberInput';
import SelectInput, {
  OptionType,
  useSelect,
} from '@/components/input/SelectInput';
import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import RequirePermission from '@/components/helper/RequirePermission';
import AlertErrorList from '@/components/helper/form/FormErrors';

import {
  ProductFormSchema,
  ProductFormValues,
  UpdateProductFormSchema,
} from '@/components/pages/master-data/product/form/ProductForm.schema';
import { isResponseError } from '@/lib/api-helper';
import {
  Product,
  CreateProductPayload,
  UpdateProductPayload,
} from '@/types/api/master-data/product';
import {
  UomApi,
  ProductCategoryApi,
  SupplierApi,
  ProductApi,
} from '@/services/api/master-data';
import { cn } from '@/lib/helper';

import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
import { ConstantsApi } from '@/services/api/constants/constants';
import type {
  TransformedConstants,
  ProductFlagMapping,
} from '@/types/api/constants/constants';
import useSWR from 'swr';
import { PRODUCT_FLAG_MAPPING } from '@/config/constant';

import { Supplier } from '@/types/api/master-data/supplier';
import Card from '@/components/Card';
import { removeArrayItemAndSync } from '@/lib/utils/formik';

interface ProductFormProps {
  type?: 'add' | 'edit' | 'detail';
  initialValues?: Product;
}

const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
  const router = useRouter();
  const deleteModal = useModal();

  const [productFormErrorMessage, setProductFormErrorMessage] = useState('');
  const [isDeleteLoading, setIsDeleteLoading] = useState(false);
  const {
    data: constants,
    error: constantsError,
    isLoading: isLoadingConstants,
  } = useSWR<TransformedConstants | undefined>(
    'constants',
    ConstantsApi.fetchTransformedConstants.bind(ConstantsApi),
    {
      shouldRetryOnError: false,
    }
  );

  const productFlagMapping: ProductFlagMapping | null = useMemo(() => {
    if (constantsError || !constants?.product_flag_mapping) {
      return PRODUCT_FLAG_MAPPING as unknown as ProductFlagMapping;
    }
    return constants.product_flag_mapping;
  }, [constants, constantsError]);

  const createProductHandler = useCallback(
    async (payload: CreateProductPayload) => {
      const res = await ProductApi.create(payload);
      if (isResponseError(res)) {
        setProductFormErrorMessage(res.message);
        return;
      }
      toast.success(res?.message as string);
      router.push('/master-data/product');
    },
    [router]
  );

  const updateProductHandler = useCallback(
    async (productId: number, payload: UpdateProductPayload) => {
      const res = await ProductApi.update(productId, payload);
      if (res?.status === 'error') {
        setProductFormErrorMessage(res.message);
        return;
      }
      toast.success(res?.message as string);
      router.refresh();
      router.push('/master-data/product');
    },
    [router]
  );

  const formikInitialValues = useMemo<ProductFormValues>(
    () => ({
      name: initialValues?.name ?? '',
      brand: initialValues?.brand ?? '',
      sku: initialValues?.sku ?? '',
      uom: initialValues?.uom
        ? { value: initialValues.uom.id, label: initialValues.uom.name }
        : undefined,
      uom_id: initialValues?.uom?.id ?? 0,
      product_category: initialValues?.product_category
        ? {
            value: initialValues.product_category.id,
            label: initialValues.product_category.name,
          }
        : undefined,
      product_category_id: initialValues?.product_category?.id ?? 0,
      product_price: initialValues?.product_price ?? '',
      selling_price: initialValues?.selling_price ?? '',
      tax: initialValues?.tax ?? '',
      expiry_period: initialValues?.expiry_period ?? '',
      suppliers: initialValues?.suppliers
        ? initialValues.suppliers.map((supplier) => ({
            supplier: {
              value: supplier.id,
              label: supplier.name,
            },
            price: supplier.price,
          }))
        : [],
      flag: initialValues?.flag ?? '',
      sub_flags: initialValues?.sub_flags ?? [],
    }),
    [initialValues]
  );

  const formik = useFormik<ProductFormValues>({
    initialValues: formikInitialValues,
    validationSchema:
      type === 'edit' ? UpdateProductFormSchema : ProductFormSchema,
    onSubmit: async (values) => {
      setProductFormErrorMessage('');
      const payload: CreateProductPayload = {
        name: values.name,
        brand: values.brand,
        sku: values.sku,
        uom_id: values.uom_id,
        product_category_id: values.product_category_id,
        product_price: parseFloat(values.product_price.toString()) || 0,
        selling_price: values.selling_price
          ? parseFloat(values.selling_price.toString()) || 0
          : undefined,
        tax: values.tax ? parseFloat(values.tax.toString()) || 0 : undefined,
        expiry_period: values.expiry_period
          ? parseFloat(values.expiry_period.toString()) || 0
          : undefined,
        suppliers: values.suppliers.map((s) => ({
          supplier_id: s.supplier?.value as number,
          price: parseFloat(s.price.toString()) || 0,
        })),
        flag: values.flag,
        sub_flags: values.sub_flags,
      };
      switch (type) {
        case 'add':
          await createProductHandler(payload);
          break;
        case 'edit':
          await updateProductHandler(initialValues?.id as number, payload);
          break;
      }
    },
  });

  const { setValues: formikSetValues } = formik;

  // UOM
  const {
    setInputValue: setUomSelectInputValue,
    options: uomOptions,
    isLoadingOptions: isLoadingUoms,
    loadMore: loadMoreUoms,
  } = useSelect(UomApi.basePath, 'id', 'name');
  const uomChangeHandler = (val: OptionType | OptionType[] | null) => {
    formik.setFieldTouched('uom', true);
    formik.setFieldValue('uom', val);
    formik.setFieldTouched('uom_id', true);
    formik.setFieldValue('uom_id', (val as OptionType)?.value);
  };

  // Product Category
  const {
    setInputValue: setCategorySelectInputValue,
    options: categoryOptions,
    isLoadingOptions: isLoadingCategories,
    loadMore: loadMoreCategories,
  } = useSelect(ProductCategoryApi.basePath, 'id', 'name');
  const categoryChangeHandler = (val: OptionType | OptionType[] | null) => {
    formik.setFieldTouched('product_category', true);
    formik.setFieldValue('product_category', val);
    formik.setFieldTouched('product_category_id', true);
    formik.setFieldValue('product_category_id', (val as OptionType)?.value);
  };

  // Supplier (multi select) - using SWR to filter by category
  const {
    setInputValue: setSupplierSelectInputValue,
    options: supplierOptions,
    isLoadingOptions: isLoadingSuppliers,
    loadMore: loadMoreSuppliers,
  } = useSelect<Supplier>(SupplierApi.basePath, 'id', 'name', 'search', {
    category: 'SAPRONAK',
  });

  const filteredSupplierOptions = useMemo(() => {
    return supplierOptions.filter((opt) => {
      return !formik.values.suppliers.some(
        (s) => s.supplier?.value === opt.value
      );
    });
  }, [supplierOptions, formik.values.suppliers]);

  const selectedFlagMapping = useMemo(() => {
    return productFlagMapping?.options.find(
      (opt) => opt.flag.value === formik.values.flag
    );
  }, [formik.values.flag, productFlagMapping]);

  const subFlagOptions = useMemo<OptionType[]>(() => {
    return selectedFlagMapping?.sub_flags ?? [];
  }, [selectedFlagMapping]);

  const selectedSubFlagValues = useMemo<OptionType[]>(() => {
    return (
      selectedFlagMapping?.sub_flags.filter((subFlag) =>
        formik.values.sub_flags?.includes(subFlag.value as string)
      ) ?? []
    );
  }, [selectedFlagMapping, formik.values.sub_flags]);

  const isSubFlagRequired = useMemo(() => {
    return selectedFlagMapping?.allow_without_sub_flag === false;
  }, [selectedFlagMapping]);

  const addSupplierHandler = () => {
    formik.setFieldValue('suppliers', [
      ...formik.values.suppliers,
      {
        supplier_id: '',
        price: formik.values.product_price,
      },
    ]);
  };

  const deleteSupplierItemHandler = (idx: number) => {
    const path = 'suppliers';

    removeArrayItemAndSync(formik, path, idx);
  };

  const deleteProductClickHandler = () => {
    deleteModal.openModal();
  };

  const confirmationModalDeleteClickHandler = async () => {
    setIsDeleteLoading(true);
    await ProductApi.delete(initialValues?.id as number);
    deleteModal.closeModal();
    toast.success('Successfully delete Product!');
    setIsDeleteLoading(false);
    router.push('/master-data/product');
  };

  const isSupplierRepeaterError = (
    column: 'supplier' | 'price',
    supplierIdx: number
  ) => {
    return (
      formik.touched.suppliers?.[supplierIdx]?.[column] &&
      Boolean(
        formik.errors.suppliers?.[supplierIdx] instanceof Object &&
          formik.errors.suppliers?.[supplierIdx]?.[column]
      )
    );
  };

  useEffect(() => {
    formikSetValues(formikInitialValues);
  }, [formikSetValues, formikInitialValues]);

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

  return (
    <>
      <section className='w-full max-w-2xl'>
        <header className='flex flex-col gap-4'>
          <Button
            href='/master-data/product'
            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 Produk'}
            {type === 'edit' && 'Edit Produk'}
            {type === 'detail' && 'Detail Produk'}
          </h1>
        </header>
        <form
          onSubmit={handleFormSubmit}
          onReset={formik.handleReset}
          className='w-full mt-8 flex flex-col gap-6'
        >
          <div className='grid grid-cols-1 gap-4'>
            <TextInput
              required
              label='Nama'
              name='name'
              placeholder='Masukkan nama...'
              value={formik.values.name}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={formik.touched.name && Boolean(formik.errors.name)}
              errorMessage={formik.errors.name}
              readOnly={type === 'detail'}
            />
            <div className='grid sm:grid-cols-2 gap-4'>
              <TextInput
                required
                label='Merek'
                name='brand'
                placeholder='Masukkan merek...'
                value={formik.values.brand}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                isError={formik.touched.brand && Boolean(formik.errors.brand)}
                errorMessage={formik.errors.brand}
                readOnly={type === 'detail'}
              />
              <TextInput
                label='SKU'
                name='sku'
                placeholder='Masukkan SKU...'
                value={formik.values.sku}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                isError={formik.touched.sku && Boolean(formik.errors.sku)}
                errorMessage={formik.errors.sku}
                readOnly={type === 'detail'}
              />
            </div>
            <div className='grid sm:grid-cols-2 gap-4'>
              <SelectInput
                required
                label='Satuan'
                placeholder='Pilih satuan...'
                value={formik.values.uom ?? undefined}
                onChange={uomChangeHandler}
                options={uomOptions}
                onInputChange={setUomSelectInputValue}
                onMenuScrollToBottom={loadMoreUoms}
                isLoading={isLoadingUoms}
                isError={
                  (formik.touched.uom || formik.touched.uom_id) &&
                  Boolean(formik.errors.uom_id)
                }
                errorMessage={formik.errors.uom_id as string}
                isDisabled={type === 'detail'}
                isClearable
              />
              <SelectInput
                required
                label='Kategori Produk'
                placeholder='Pilih kategori produk...'
                value={formik.values.product_category ?? undefined}
                onChange={categoryChangeHandler}
                options={categoryOptions}
                onInputChange={setCategorySelectInputValue}
                onMenuScrollToBottom={loadMoreCategories}
                isLoading={isLoadingCategories}
                isError={
                  (formik.touched.product_category ||
                    formik.touched.product_category_id) &&
                  Boolean(formik.errors.product_category_id)
                }
                errorMessage={formik.errors.product_category_id as string}
                isDisabled={type === 'detail'}
                isClearable
              />
            </div>
            <div className='grid sm:grid-cols-2 gap-4'>
              <NumberInput
                required
                label='Harga Produk'
                name='product_price'
                placeholder='Masukkan harga produk...'
                value={formik.values.product_price}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                decimalScale={2}
                allowNegative={false}
                thousandSeparator=','
                decimalSeparator='.'
                inputPrefix='Rp '
                isError={
                  formik.touched.product_price &&
                  Boolean(formik.errors.product_price)
                }
                errorMessage={formik.errors.product_price as string}
                readOnly={type === 'detail'}
              />
              <NumberInput
                label='Harga Jual'
                name='selling_price'
                placeholder='Masukkan harga jual...'
                value={formik.values.selling_price}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                decimalScale={2}
                allowNegative={false}
                thousandSeparator=','
                decimalSeparator='.'
                inputPrefix='Rp '
                isError={
                  formik.touched.selling_price &&
                  Boolean(formik.errors.selling_price)
                }
                errorMessage={formik.errors.selling_price as string}
                readOnly={type === 'detail'}
              />
            </div>
            <div className='grid sm:grid-cols-2 gap-4'>
              <NumberInput
                label='Pajak (%)'
                name='tax'
                placeholder='Masukkan pajak...'
                value={formik.values.tax}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                decimalScale={2}
                allowNegative={false}
                thousandSeparator=','
                decimalSeparator='.'
                inputSuffix='%'
                isError={formik.touched.tax && Boolean(formik.errors.tax)}
                errorMessage={formik.errors.tax as string}
                readOnly={type === 'detail'}
              />
              <NumberInput
                label='Periode Kadaluarsa (hari)'
                name='expiry_period'
                placeholder='Masukkan periode kadaluarsa...'
                value={formik.values.expiry_period}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                decimalScale={0}
                allowNegative={false}
                thousandSeparator=','
                decimalSeparator='.'
                inputSuffix='hari'
                isError={
                  formik.touched.expiry_period &&
                  Boolean(formik.errors.expiry_period)
                }
                errorMessage={formik.errors.expiry_period as string}
                readOnly={type === 'detail'}
              />
            </div>
            <div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
              <SelectInput
                required
                label='Flags'
                placeholder='Pilih flags...'
                value={productFlagMapping?.flags.find(
                  (opt) => opt.value === formik.values.flag
                )}
                onChange={(val) => {
                  const selectedFlag = String((val as OptionType)?.value ?? '');
                  formik.setFieldValue('flag', selectedFlag);
                  formik.setFieldValue('sub_flags', []);
                }}
                options={productFlagMapping?.flags ?? []}
                isLoading={isLoadingConstants && !productFlagMapping}
                isError={formik.touched.flag && Boolean(formik.errors.flag)}
                errorMessage={formik.errors.flag as string}
                isDisabled={type === 'detail'}
                isClearable
              />

              <SelectInput
                label='Kategori Flags'
                placeholder='Pilih kategori flags...'
                isMulti
                required={isSubFlagRequired}
                value={selectedSubFlagValues}
                onChange={(val) => {
                  const arr = Array.isArray(val) ? val : val ? [val] : [];
                  formik.setFieldValue(
                    'sub_flags',
                    arr.map((v) => String((v as OptionType).value))
                  );
                }}
                options={subFlagOptions}
                isLoading={isLoadingConstants && !productFlagMapping}
                isError={
                  formik.touched.sub_flags && Boolean(formik.errors.sub_flags)
                }
                errorMessage={formik.errors.sub_flags as string}
                isDisabled={type === 'detail' || !formik.values.flag}
                closeMenuOnSelect={false}
                isClearable
              />
            </div>

            <div className='grid sm:grid-cols-1 gap-4'>
              {type !== 'detail' && formik.values.suppliers.length === 0 && (
                <Button
                  type='button'
                  color='success'
                  onClick={addSupplierHandler}
                  className='w-fit mx-auto'
                >
                  <Icon icon='ic:round-plus' width={24} height={24} /> Tambah
                  Supplier
                </Button>
              )}

              {formik.values.suppliers.length > 0 && (
                <Card
                  className={{
                    wrapper: 'w-full',
                    body: 'p-4 shadow',
                  }}
                >
                  <div className='mb-4 text-center'>
                    <h4 className='font-bold text-xl'>Supplier</h4>
                  </div>

                  <div className='overflow-x-auto'>
                    <table className='table'>
                      <thead>
                        <tr>
                          <th className='after:content-["*"] after:text-red-500 after:ml-0.5'>
                            Supplier
                          </th>
                          <th className='after:content-["*"] after:text-red-500 after:ml-0.5'>
                            Harga
                          </th>
                          <th>Aksi</th>
                        </tr>
                      </thead>

                      <tbody>
                        {formik.values.suppliers.map((supplier, idx) => (
                          <tr key={idx}>
                            <td className='p-2 w-full max-w-1/2'>
                              <SelectInput
                                placeholder='Pilih Supplier'
                                options={filteredSupplierOptions}
                                onInputChange={setSupplierSelectInputValue}
                                onMenuScrollToBottom={loadMoreSuppliers}
                                isLoading={isLoadingSuppliers}
                                value={formik.values.suppliers[idx].supplier}
                                onChange={(val) => {
                                  formik.setFieldValue(
                                    `suppliers.${idx}.supplier`,
                                    val
                                  );
                                }}
                                isError={isSupplierRepeaterError(
                                  'supplier',
                                  idx
                                )}
                                isClearable
                                isDisabled={type === 'detail'}
                                className={{
                                  wrapper: 'min-w-48 w-full',
                                }}
                              />
                            </td>
                            <td className='p-2 w-full max-w-1/2'>
                              <NumberInput
                                required
                                name={`suppliers.${idx}.price`}
                                placeholder='Masukkan harga...'
                                value={formik.values.suppliers[idx].price}
                                onChange={formik.handleChange}
                                onBlur={formik.handleBlur}
                                decimalScale={2}
                                allowNegative={false}
                                thousandSeparator=','
                                decimalSeparator='.'
                                inputPrefix='Rp '
                                isError={isSupplierRepeaterError('price', idx)}
                                readOnly={type === 'detail'}
                                className={{
                                  wrapper: 'min-w-48 w-full',
                                }}
                              />
                            </td>
                            {type !== 'detail' && (
                              <td>
                                <Button
                                  type='button'
                                  color='error'
                                  onClick={() => deleteSupplierItemHandler(idx)}
                                >
                                  <Icon
                                    icon='material-symbols:delete-outline-rounded'
                                    width={24}
                                    height={24}
                                  />
                                </Button>
                              </td>
                            )}
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>

                  {type !== 'detail' && (
                    <div className='w-full flex flex-row justify-center'>
                      <Button
                        type='button'
                        color='success'
                        onClick={addSupplierHandler}
                      >
                        <Icon icon='ic:round-plus' width={24} height={24} />{' '}
                        Tambah Supplier
                      </Button>
                    </div>
                  )}
                </Card>
              )}
            </div>
          </div>
          <div className='flex flex-row justify-between gap-2 flex-wrap'>
            {type !== 'add' && (
              <div className='flex flex-row justify-start gap-2'>
                <RequirePermission permissions='lti.master.products.delete'>
                  <Button
                    type='button'
                    color='error'
                    onClick={deleteProductClickHandler}
                    className='px-4'
                  >
                    <Icon
                      icon='material-symbols:delete-outline-rounded'
                      width={24}
                      height={24}
                      className='justify-start text-sm'
                    />
                    Delete
                  </Button>
                </RequirePermission>
                {type !== 'edit' && (
                  <RequirePermission permissions='lti.master.products.update'>
                    <Button
                      type='button'
                      color='warning'
                      href={`/master-data/product/detail/edit/?productId=${initialValues?.id}`}
                      className='px-4'
                    >
                      <Icon
                        icon='material-symbols:edit-outline'
                        width={24}
                        height={24}
                        className='justify-start text-sm'
                      />
                      Edit
                    </Button>
                  </RequirePermission>
                )}
              </div>
            )}

            <div className='mb-4 w-full'>
              {productFormErrorMessage && (
                <div role='alert' className='alert alert-error'>
                  <Icon
                    icon='material-symbols:error-outline'
                    width={24}
                    height={24}
                  />
                  <span>{productFormErrorMessage}</span>
                </div>
              )}

              <AlertErrorList formErrorList={formErrorList} onClose={close} />
            </div>

            {type !== 'detail' && (
              <div
                className={cn('flex flex-row justify-end gap-2', {
                  'w-full': type === 'add',
                })}
              >
                <Button type='reset' color='warning' className='px-4'>
                  Reset
                </Button>
                <Button
                  type='submit'
                  color='primary'
                  isLoading={formik.isSubmitting}
                  disabled={formik.isSubmitting}
                  className='px-4'
                >
                  Submit
                </Button>
              </div>
            )}
          </div>
        </form>
      </section>
      {type !== 'add' && (
        <ConfirmationModal
          ref={deleteModal.ref}
          type='error'
          text={`Apakah anda yakin ingin menghapus data Produk ini (${initialValues?.name})?`}
          secondaryButton={{
            text: 'Tidak',
          }}
          primaryButton={{
            text: 'Ya',
            color: 'error',
            isLoading: isDeleteLoading,
            onClick: confirmationModalDeleteClickHandler,
          }}
        />
      )}
    </>
  );
};

export default ProductForm;
