import { useEffect, useState } from 'react';
import { useRequest } from 'ahooks';
import { joinURL } from 'ufo';
import { Box } from '@mui/material';
import { CheckoutProvider, useSessionContext, useSubmitFeature } from '@blocklet/payment-react-headless';

import api from '../libs/api';
import { getPrefix, mergeExtraParams } from '../libs/util';
import { PaymentThemeProvider } from '../theme';
import { useMobile } from '../hooks/mobile';
import type { CheckoutV2Props } from './types';
import CheckoutLayout from './layouts/checkout-layout';
import ScenarioRouter from './panels/left/scenario-router';
import PaymentPanel from './panels/right/payment-panel';
import CheckoutDialogs from './components/dialogs/checkout-dialogs';
import LoadingView from './views/loading-view';
import ErrorView from './views/error-view';
import SuccessView from './views/success-view';

// Deduplicated plink_ → cs_ resolution
const plinkPromises: Record<string, Promise<{ checkoutSession: { id: string } }>> = {};
function startFromPaymentLink(
  id: string,
  params?: Record<string, string>
): Promise<{ checkoutSession: { id: string } }> {
  if (!plinkPromises[id]) {
    plinkPromises[id] = api
      .post(`/api/checkout-sessions/start/${id}?${mergeExtraParams(params)}`)
      .then((res: any) => res?.data)
      .finally(() => {
        setTimeout(() => {
          delete plinkPromises[id];
        }, 3000);
      });
  }
  return plinkPromises[id];
}

// Inner router: must be rendered inside CheckoutProvider
function CheckoutRouter({
  onPaid = undefined,
  onError = undefined,
  mode = 'inline',
}: {
  onPaid?: (result: any) => void;
  onError?: (err: Error) => void;
  mode?: string;
}) {
  const { isLoading, error, errorCode, session } = useSessionContext();
  const submit = useSubmitFeature();
  const { isMobile } = useMobile();

  useEffect(() => {
    if (error && onError) {
      onError(new Error(error));
    }
  }, [error, onError]);

  useEffect(() => {
    if (submit.status === 'completed' && submit.result && onPaid) {
      onPaid(submit.result);
    }
  }, [submit.status, submit.result, onPaid]);

  if (isLoading) {
    return <LoadingView mode={mode} />;
  }

  if (error) {
    return <ErrorView error={error} errorCode={errorCode} mode={mode} />;
  }

  const isCompleted = submit.status === 'completed';
  const mobileCompleted = isCompleted && isMobile;

  return (
    <>
      <CheckoutLayout
        left={
          mobileCompleted ? null : (
            <Box
              sx={{
                flex: 1,
                display: 'flex',
                flexDirection: 'column',
                ...(isCompleted
                  ? { opacity: 0.45, pointerEvents: 'none', filter: 'grayscale(0.3)', transition: 'all 0.5s ease' }
                  : {}),
              }}>
              <ScenarioRouter />
            </Box>
          )
        }
        right={isCompleted ? <SuccessView submit={submit} session={session} /> : <PaymentPanel />}
        mode={mode}
      />
      {!isCompleted && <CheckoutDialogs />}
    </>
  );
}

export default function CheckoutV2({
  id,
  onPaid,
  onError,
  theme = 'default',
  mode = 'inline',
  extraParams = {},
}: CheckoutV2Props) {
  if (!id.startsWith('plink_') && !id.startsWith('cs_')) {
    throw new Error('Either a checkoutSession or a paymentLink id is required.');
  }

  const isPaymentLink = id.startsWith('plink_');
  const [resolvedSessionId, setResolvedSessionId] = useState<string | null>(isPaymentLink ? null : id);

  // Resolve plink_ to cs_
  useRequest(
    async () => {
      if (!isPaymentLink) return null;
      const data = await startFromPaymentLink(id, extraParams);
      const csId = data?.checkoutSession?.id;
      if (csId) {
        setResolvedSessionId(csId);
        if (mode === 'standalone') {
          window.history.replaceState(
            null,
            '',
            joinURL(getPrefix(), `/checkout/pay/${csId}?${mergeExtraParams(extraParams)}`)
          );
        }
      }
      return data;
    },
    { ready: isPaymentLink }
  );

  if (!resolvedSessionId) {
    return <LoadingView mode={mode} />;
  }

  const content = (
    <CheckoutProvider sessionId={resolvedSessionId}>
      <CheckoutRouter onPaid={onPaid} onError={onError} mode={mode} />
    </CheckoutProvider>
  );

  if (theme === 'inherit') {
    return content;
  }
  if (theme && typeof theme === 'object') {
    return <PaymentThemeProvider theme={theme}>{content}</PaymentThemeProvider>;
  }
  return <PaymentThemeProvider>{content}</PaymentThemeProvider>;
}
