'use client';

import Button from '@/components/Button';
import AlertErrorList from '@/components/helper/form/FormErrors';
import { FormHeader } from '@/components/helper/form/FormHeader';
import NumberInput from '@/components/input/NumberInput';
import SelectInput, { useSelect } from '@/components/input/SelectInput';
import TextArea from '@/components/input/TextArea';
import TextInput from '@/components/input/TextInput';
import {
  InitialBalanceFormSchema,
  InitialBalanceFormValues,
} from '@/components/pages/finance/add/initial-balance/FormFinanceAddInitialBalance.schema';
import {
  FINANCE_INITIAL_BALANCE_TYPE_OPTIONS,
  FINANCE_PARTY_TYPE_OPTIONS,
} from '@/config/constant';
import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { formatTitleCase } from '@/lib/helper';
import { FinanceApi } from '@/services/api/finance';
import { BankApi, CustomerApi, SupplierApi } from '@/services/api/master-data';
import {
  CreateInitialBalance,
  Finance,
  UpdateInitialBalance,
} from '@/types/api/finance/finance';
import { Bank } from '@/types/api/master-data/bank';
import { Icon } from '@iconify/react';
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';

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

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

  // ===== Formik =====
  const formikInitialValues = useMemo((): InitialBalanceFormValues => {
    // Type assertion to handle potential initial_balance_type field
    // const extendedInitialValues = initialValues as Finance & {
    //   initial_balance_type?: string;
    // };

    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,
          }
        : null,
      bank_id_option: initialValues?.bank
        ? {
            label: initialValues.bank?.name,
            value: initialValues.bank?.id,
          }
        : null,
      reference_number: initialValues?.reference_number || '',
      initial_balance_type_option:
        (initialValues?.nominal ?? 0) < 0
          ? FINANCE_INITIAL_BALANCE_TYPE_OPTIONS.find(
              (option) => option.value === 'NEGATIVE'
            ) || null
          : FINANCE_INITIAL_BALANCE_TYPE_OPTIONS.find(
              (option) => option.value === 'POSITIVE'
            ) || null,
      nominal: initialValues?.nominal?.toString() || '',
      note: initialValues?.notes || '',
    };
  }, [initialValues]);

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

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

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

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

  // ===== Helper Functions =====
  const transformFormValuesToPayload = (
    values: InitialBalanceFormValues
  ): CreateInitialBalance => {
    return {
      party_type: (values.party_type_option?.value as string) || '',
      party_id: Number(values.party_id_option?.value) || 0,
      bank_id: Number(values.bank_id_option?.value) || 0,
      reference_number: values.reference_number,
      initial_balance_type:
        (values.initial_balance_type_option?.value as string) || '',
      nominal: Number(values.nominal.replace(/\D/g, '')) || 0,
      note: values.note,
    };
  };

  // ===== Handler =====
  const createInitialBalance = useCallback(
    async (payload: CreateInitialBalance) => {
      const response = await FinanceApi.createInitialBalances(payload);

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

      toast.success('Saldo awal berhasil ditambahkan');
      router.refresh();
      router.push('/finance');
    },
    [router]
  );

  const updateInitialBalance = useCallback(
    async (financeId: number, payload: UpdateInitialBalance) => {
      const response = await FinanceApi.updateInitialBalances(
        financeId,
        payload
      );

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

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

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

  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'} Saldo Awal`}
            backUrl='/finance'
          />
          <form className='flex flex-col gap-4' onSubmit={handleFormSubmit}>
            <SelectInput
              label='Jenis Pihak'
              placeholder='Pilih jenis pihak'
              options={FINANCE_PARTY_TYPE_OPTIONS}
              value={formik.values.party_type_option}
              onInputChange={setPartyInputValue}
              onMenuScrollToBottom={loadMorePartyOptions}
              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
                  : ''
              }
              required
              isDisabled={type === 'edit'}
              isClearable
            />
            <SelectInput
              label={
                formik.values.party_type_option?.value
                  ? formatTitleCase(
                      formik.values.party_type_option.value as string
                    )
                  : 'Pilih Jenis Pihak Dahulu'
              }
              placeholder={`Pilih ${formik.values.party_type_option?.value ? formatTitleCase(formik.values.party_type_option.value as string) : 'jenis pihak dahulu'}`}
              options={partyOptions}
              value={formik.values.party_id_option}
              onInputChange={setPartyInputValue}
              onMenuScrollToBottom={loadMorePartyOptions}
              onChange={(value) => {
                formik.setFieldValue('party_id_option', value);
              }}
              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')
              }
            />
            <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}
              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
                  : ''
              }
              isClearable
            />
            <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
            />
            <SelectInput
              label='Tipe Saldo Awal'
              placeholder='Pilih tipe saldo awal'
              options={FINANCE_INITIAL_BALANCE_TYPE_OPTIONS}
              value={formik.values.initial_balance_type_option}
              onChange={(value) => {
                formik.setFieldValue('initial_balance_type_option', value);
              }}
              isError={Boolean(
                formik.touched.initial_balance_type_option &&
                  formik.errors.initial_balance_type_option
              )}
              errorMessage={
                formik.touched.initial_balance_type_option &&
                formik.errors.initial_balance_type_option
                  ? formik.errors.initial_balance_type_option
                  : ''
              }
              required
              isClearable
              isDisabled={type == 'edit'}
            />
            <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
                  : ''
              }
              allowNegative={false}
              startAdornment={
                formik.values.initial_balance_type_option?.value ===
                'POSITIVE' ? (
                  <Icon icon='mdi:plus' />
                ) : formik.values.initial_balance_type_option?.value ===
                  'NEGATIVE' ? (
                  <Icon icon='mdi:minus' />
                ) : (
                  ''
                )
              }
              required
            />
            <TextArea
              label='Catatan'
              placeholder='Masukkan catatan'
              name='note'
              value={formik.values.note}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              isError={Boolean(formik.touched.note && formik.errors.note)}
              errorMessage={
                formik.touched.note && formik.errors.note
                  ? formik.errors.note
                  : ''
              }
              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 FormFinanceAddInitialBalance;
