'use client';

import Button from '@/components/Button';
import AlertErrorList from '@/components/helper/form/FormErrors';
import { FormHeader } from '@/components/helper/form/FormHeader';
import DateInput from '@/components/input/DateInput';
import NumberInput from '@/components/input/NumberInput';
import SelectInput, {
  OptionType,
  useSelect,
} from '@/components/input/SelectInput';
import TextArea from '@/components/input/TextArea';
import TextInput from '@/components/input/TextInput';
import {
  FinanceFormSchema,
  FinanceFormValues,
} from '@/components/pages/finance/add/FormFinanceAdd.schema';
import {
  FINANCE_PARTY_TYPE_OPTIONS,
  FINANCE_PAYMENT_METHOD_OPTIONS,
} from '@/config/constant';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { formatDate, formatTitleCase } from '@/lib/helper';
import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
import { FinanceApi } from '@/services/api/finance';
import { BankApi, CustomerApi, SupplierApi } from '@/services/api/master-data';
import {
  CreateFinancePayment,
  Finance,
  UpdateFinancePayment,
} from '@/types/api/finance/finance';
import { Bank } from '@/types/api/master-data/bank';
import { useFormik } from 'formik';
import { useRouter } from 'next/navigation';
import { useCallback, useMemo, useState } from 'react';
import toast from 'react-hot-toast';
import Alert from '@/components/Alert';
import { Icon } from '@iconify/react';

interface FormFinanceAddProps {
  type?: 'add' | 'edit';
  initialValues?: Finance;
}

interface PartyCommonProps {
  id: number;
  name: string;
  account_number: string;
}

const FormFinanceAdd = ({
  type = 'add',
  initialValues,
}: FormFinanceAddProps) => {
  const router = useRouter();
  const [serverErrorMessage, setServerErrorMessage] = useState('');

  // ===== Formik =====
  const formikInitialValues = useMemo((): FinanceFormValues => {
    return {
      party_type_option:
        FINANCE_PARTY_TYPE_OPTIONS.find(
          (option) => option.value === initialValues?.party?.type
        ) || null,
      party_id_option: initialValues?.party
        ? {
            label: initialValues?.party?.name || '',
            value: initialValues?.party?.id || 0,
          }
        : null,
      payment_date: initialValues?.payment_date || '',
      payment_method_option:
        FINANCE_PAYMENT_METHOD_OPTIONS.find(
          (option) => option.value === initialValues?.payment_method
        ) || null,
      bank_id_option: initialValues?.bank
        ? {
            label: initialValues?.bank?.name,
            value: initialValues?.bank?.id,
          }
        : null,
      party_account_number: initialValues?.party?.account_number || '',
      reference_number: initialValues?.reference_number || '',
      nominal: initialValues?.nominal.toString() || '',
      notes: initialValues?.notes || '',
    };
  }, [initialValues]);

  const formik = useFormik<FinanceFormValues>({
    initialValues: formikInitialValues,
    validationSchema: FinanceFormSchema,
    validateOnChange: true,
    validateOnBlur: true,
    onSubmit: async (values) => {
      const payload = transformFormValuesToPayload(values);

      switch (type) {
        case 'add':
          await createFinance(payload);
          break;

        case 'edit':
          if (initialValues?.id) {
            await updateFinance(initialValues.id, payload);
          }
          break;
      }
    },
  });

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

  // ===== Options =====
  const {
    options: partyOptions,
    isLoadingOptions: isLoadingPartyOptions,
    rawData: partyRawData,
    setInputValue: setPartyInputValue,
    loadMore: loadMorePartyOptions,
  } = useSelect<PartyCommonProps>(
    formik.values.party_type_option?.value === 'CUSTOMER'
      ? CustomerApi.basePath
      : SupplierApi.basePath,
    'id',
    'name'
  );
  const {
    options: bankOptions,
    rawData: bankRawData,
    isLoadingOptions: isLoadingBankOptions,
    setInputValue: setBankInputValue,
    loadMore: loadMoreBankOptions,
  } = useSelect<Bank>(BankApi.basePath, 'id', 'name');

  // ===== Helper Functions =====
  const transformFormValuesToPayload = (
    values: FinanceFormValues
  ): CreateFinancePayment => {
    return {
      party_id: Number(values.party_id_option?.value) || 0,
      party_type: (values.party_type_option?.value as string) || '',
      payment_date: formatDate(values.payment_date, 'YYYY-MM-DD'),
      payment_method: (values.payment_method_option?.value as string) || '',
      bank_id: Number(values.bank_id_option?.value) || 0,
      reference_number: values.reference_number,
      nominal: Number(values.nominal.replace(/\D/g, '')) || 0,
      notes: values.notes,
    };
  };

  // ===== Handler =====
  const createFinance = useCallback(
    async (payload: CreateFinancePayment) => {
      const response = await FinanceApi.create(payload);

      if (isResponseError(response)) {
        toast.error(response.message);
        setServerErrorMessage(response.message);
        return;
      }

      toast.success('Data berhasil ditambahkan');
      router.refresh();
      router.push('/finance');
    },
    [router]
  );
  const updateFinance = useCallback(
    async (financeId: number, payload: UpdateFinancePayment) => {
      const response = await FinanceApi.update(financeId, payload);

      if (isResponseError(response)) {
        toast.error(response.message);
        setServerErrorMessage(response.message);
        return;
      }

      toast.success('Data berhasil diperbarui');
      router.refresh();
      router.push('/finance');
    },
    [router]
  );

  return (
    <>
      <section className='w-full max-w-xl mx-auto'>
        <div className='flex flex-col gap-6 p-6'>
          <FormHeader
            title={`${type === 'add' ? 'Tambah' : 'Ubah'} Data Keuangan`}
            backUrl='/finance'
          />
          <form className='flex flex-col gap-4' onSubmit={handleFormSubmit}>
            <SelectInput
              label='Jenis Transaksi'
              placeholder='Pilih jenis transaksi'
              options={FINANCE_PARTY_TYPE_OPTIONS}
              value={formik.values.party_type_option}
              onChange={(value) => {
                formik.setFieldValue('party_type_option', value);
                formik.setFieldValue('party_id_option', null);
                formik.setFieldValue('party_account_number', '');
              }}
              isError={Boolean(
                formik.touched.party_type_option &&
                  formik.errors.party_type_option
              )}
              errorMessage={
                formik.touched.party_type_option &&
                formik.errors.party_type_option
                  ? formik.errors.party_type_option
                  : ''
              }
              isDisabled={type === 'edit'}
              required
              isClearable
            />
            <SelectInput
              label={
                formik.values.party_type_option?.value
                  ? formatTitleCase(
                      formik.values.party_type_option.value as string
                    )
                  : 'Pilih Jenis Transaksi Dahulu'
              }
              placeholder={`Pilih ${formik.values.party_type_option?.value ? formatTitleCase(formik.values.party_type_option.value as string) : 'jenis transaksi dahulu'}`}
              options={partyOptions}
              value={formik.values.party_id_option}
              onInputChange={setPartyInputValue}
              onMenuScrollToBottom={loadMorePartyOptions}
              onChange={(value) => {
                formik.setFieldValue('party_id_option', value);
                if (isResponseSuccess(partyRawData) && value) {
                  formik.setFieldValue(
                    'party_account_number',
                    partyRawData.data?.find(
                      (item) => item.id === (value as OptionType)?.value
                    )?.account_number || ''
                  );
                }
              }}
              isLoading={isLoadingPartyOptions}
              isError={Boolean(
                formik.touched.party_id_option && formik.errors.party_id_option
              )}
              errorMessage={
                formik.touched.party_id_option && formik.errors.party_id_option
                  ? formik.errors.party_id_option
                  : ''
              }
              required
              isClearable
              isDisabled={
                !formik.values.party_type_option?.value ||
                (type === 'edit' &&
                  formik.values.party_type_option.value == 'SUPPLIER')
              }
            />
            <DateInput
              label='Tanggal'
              placeholder='Pilih tanggal'
              name='payment_date'
              value={formik.values.payment_date}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={Boolean(
                formik.touched.payment_date && formik.errors.payment_date
              )}
              errorMessage={
                formik.touched.payment_date && formik.errors.payment_date
                  ? formik.errors.payment_date
                  : ''
              }
              required
            />
            <SelectInput
              label='Metode Pembayaran'
              placeholder='Pilih metode pembayaran'
              options={FINANCE_PAYMENT_METHOD_OPTIONS}
              value={formik.values.payment_method_option}
              onChange={(value) => {
                formik.setFieldValue('payment_method_option', value);
              }}
              isError={Boolean(
                formik.touched.payment_method_option &&
                  formik.errors.payment_method_option
              )}
              errorMessage={
                formik.touched.payment_method_option &&
                formik.errors.payment_method_option
                  ? formik.errors.payment_method_option
                  : ''
              }
              required
              isClearable
            />
            <SelectInput
              label='Bank'
              placeholder='Pilih bank'
              options={
                isResponseSuccess(bankRawData)
                  ? bankOptions.map((option) => ({
                      label:
                        bankRawData.data?.find(
                          (item) => item.id === option.value
                        )?.alias +
                        ' - ' +
                        bankRawData.data?.find(
                          (item) => item.id === option.value
                        )?.account_number +
                        ' - ' +
                        bankRawData.data?.find(
                          (item) => item.id === option.value
                        )?.owner,
                      value: option.value,
                    }))
                  : []
              }
              value={formik.values.bank_id_option}
              onInputChange={setBankInputValue}
              onMenuScrollToBottom={loadMoreBankOptions}
              onChange={(value) => {
                formik.setFieldValue('bank_id_option', value);
              }}
              isLoading={isLoadingBankOptions}
              isError={Boolean(
                formik.touched.bank_id_option && formik.errors.bank_id_option
              )}
              errorMessage={
                formik.touched.bank_id_option && formik.errors.bank_id_option
                  ? formik.errors.bank_id_option
                  : ''
              }
              required
              isClearable
            />
            <TextInput
              label={`Nomor Rekening ${formik.values.party_type_option?.value ? formatTitleCase(formik.values.party_type_option.value as string) : 'Pihak'}`}
              placeholder={`Masukkan nomor rekening ${formik.values.party_type_option?.value ? formatTitleCase(formik.values.party_type_option.value as string) : 'pihak'}`}
              name='party_account_number'
              value={formik.values.party_account_number}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={Boolean(
                formik.touched.party_account_number &&
                  formik.errors.party_account_number
              )}
              errorMessage={
                formik.touched.party_account_number &&
                formik.errors.party_account_number
                  ? formik.errors.party_account_number
                  : ''
              }
              required
              readOnly
            />
            <TextInput
              label='Nomor Referensi'
              placeholder='Masukkan nomor referensi'
              name='reference_number'
              value={formik.values.reference_number}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={Boolean(
                formik.touched.reference_number &&
                  formik.errors.reference_number
              )}
              errorMessage={
                formik.touched.reference_number &&
                formik.errors.reference_number
                  ? formik.errors.reference_number
                  : ''
              }
              required
            />
            <NumberInput
              label='Nominal'
              placeholder='Masukkan nominal'
              name='nominal'
              value={formik.values.nominal}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={Boolean(formik.touched.nominal && formik.errors.nominal)}
              errorMessage={
                formik.touched.nominal && formik.errors.nominal
                  ? formik.errors.nominal
                  : ''
              }
              required
            />
            <TextArea
              label='Catatan'
              placeholder='Masukkan catatan'
              name='notes'
              value={formik.values.notes}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={Boolean(formik.touched.notes && formik.errors.notes)}
              errorMessage={
                formik.touched.notes && formik.errors.notes
                  ? formik.errors.notes
                  : ''
              }
              required
            />
            <AlertErrorList formErrorList={formErrorList} onClose={close} />
            {serverErrorMessage && (
              <Alert color='error'>
                <Icon icon='mdi:alert' />
                {serverErrorMessage}
                <Button color='error' onClick={() => setServerErrorMessage('')}>
                  <Icon icon='mdi:close' />
                </Button>
              </Alert>
            )}
            <div className='flex justify-center gap-4'>
              <Button
                type='reset'
                color='warning'
                className='w-min-24'
                onClick={() => formik.resetForm()}
                disabled={formik.isSubmitting}
              >
                Reset
              </Button>
              <Button
                type='submit'
                className='w-min-24'
                disabled={formik.isSubmitting}
              >
                Submit
              </Button>
            </div>
          </form>
        </div>
      </section>
    </>
  );
};

export default FormFinanceAdd;
