import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import Toast from '@arcblock/ux/lib/Toast';
import { ConfirmDialog, api, formatError } from '@blocklet/payment-react';
import type { TInvoiceExpanded } from '@blocklet/payment-types';
import { useRequest, useSetState } from 'ahooks';
import { useNavigate } from 'react-router-dom';
import type { LiteralUnion } from 'type-fest';

import Actions from '../actions';
import ClickBoundary from '../click-boundary';

type Props = {
  data: TInvoiceExpanded;
  variant?: LiteralUnion<'compact' | 'normal', string>;
  onChange: (action: string) => void;

  mode?: 'admin' | 'customer';
};

const fetchStakingData = (id: string): Promise<{ value: string }> => {
  return api.get(`/api/invoices/${id}/return-stake`).then((res: any) => res.data);
};

export default function InvoiceActions({ data, variant = 'compact', onChange, mode = 'admin' }: Props) {
  const { t } = useLocaleContext();
  const navigate = useNavigate();
  const [state, setState] = useSetState({
    action: '',
    loading: false,
  });

  const isStakeInvoice = ['stake', 'stake_overdraft_protection'].includes(data.billing_reason);
  const hasPaid = data.status === 'paid';
  const isAdmin = mode === 'admin';
  const showReturnStake = isAdmin && isStakeInvoice && hasPaid && data.paymentMethod?.type === 'arcblock';

  const {
    data: stakeResult = {
      value: '0',
    },
    runAsync: fetchStakeResultAsync,
  } = useRequest(
    () => {
      if (showReturnStake) {
        return fetchStakingData(data.id);
      }
      return Promise.resolve({ value: '0' });
    },
    {
      manual: true,
    }
  );

  const handleAction = async () => {
    try {
      setState({ loading: true });
      if (state.action === 'return-stake') {
        const result = await api.post(`/api/invoices/${data.id}/return-stake`).then((res: any) => res.data);
        if (result.success) {
          Toast.success(t('admin.invoice.returnStake.success'));
        } else {
          Toast.error(result.error);
        }
      }
      if (state.action === 'retry-uncollectible') {
        await api
          .get('/api/invoices/retry-uncollectible', {
            params: {
              invoiceId: data.id,
            },
          })
          .then((res: any) => res.data);
        Toast.success(t('admin.invoice.retryUncollectible.success'));
      }
      if (state.action === 'void') {
        await api.post(`/api/invoices/${data.id}/void`).then((res: any) => res.data);
        Toast.success(t('admin.invoice.void.success'));
      }
      onChange(state.action);
    } catch (err) {
      console.error(err);
      Toast.error(formatError(err));
    } finally {
      setState({ loading: false, action: '' });
    }
  };

  const actions = [
    isAdmin && {
      label: t('admin.invoice.edit'),
      handler: () => setState({ action: 'edit' }),
      color: 'primary',
      disabled: data.status !== 'draft',
    },
    isAdmin && {
      label: t('admin.invoice.duplicate'),
      handler: () => setState({ action: 'duplicate' }),
      color: 'primary',
      disabled: data.status !== 'draft',
      divider: true,
    },
    isAdmin &&
      data.status === 'uncollectible' && {
        label: t('admin.invoice.retryUncollectible.title'),
        handler: () => setState({ action: 'retry-uncollectible' }),
        color: 'primary',
      },
    showReturnStake &&
      stakeResult &&
      stakeResult.value !== '0' && {
        label: t('admin.invoice.returnStake.title'),
        handler: () => setState({ action: 'return-stake' }),
        color: 'primary',
        divider: true,
      },
    isAdmin &&
      !['paid', 'void', 'draft'].includes(data.status) && {
        label: t('admin.invoice.void.title'),
        handler: () => setState({ action: 'void' }),
        color: 'primary',
        divider: true,
      },
    {
      label: t('admin.customer.view'),
      handler: () => {
        if (isAdmin) {
          navigate(`/admin/customers/${data.customer_id}`);
        } else {
          navigate('/customer');
        }
      },
      color: 'primary',
    },
  ].filter(Boolean);

  if (variant === 'compact') {
    actions.push({
      label: t('admin.invoice.view'),
      handler: () => {
        if (isAdmin) {
          navigate(`/admin/billing/${data.id}`);
        } else {
          navigate(`/customer/invoice/${data.id}`);
        }
      },
      color: 'primary',
    });
  }

  return (
    <ClickBoundary>
      <Actions variant={variant} actions={actions as any} onOpenCallback={fetchStakeResultAsync} />
      {state.action === 'retry-uncollectible' && (
        <ConfirmDialog
          onConfirm={handleAction}
          onCancel={() => setState({ action: '' })}
          title={t('admin.invoice.retryUncollectible.title')}
          message={t('admin.invoice.retryUncollectible.tip')}
          loading={state.loading}
          color="primary"
        />
      )}
      {state.action === 'return-stake' && (
        <ConfirmDialog
          onConfirm={handleAction}
          onCancel={() => setState({ action: '' })}
          title={t('admin.invoice.returnStake.title')}
          message={t('admin.invoice.returnStake.tip')}
          loading={state.loading}
        />
      )}
      {state.action === 'void' && (
        <ConfirmDialog
          onConfirm={handleAction}
          onCancel={() => setState({ action: '' })}
          title={t('admin.invoice.void.title')}
          message={t('admin.invoice.void.tip')}
          loading={state.loading}
        />
      )}
    </ClickBoundary>
  );
}
