import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import SettingsIcon from '@mui/icons-material/Settings';
import {
  Box,
  Collapse,
  Dialog,
  DialogTitle,
  DialogContent,
  Fade,
  IconButton,
  Stack,
  Tooltip,
  Typography,
} from '@mui/material';
import type { ReactNode } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import SlippageConfig from './slippage-config';
import type { SlippageConfigValue } from './slippage-config';

type QuoteDetailRow = {
  label: string;
  value: ReactNode;
  isSlippage?: boolean;
  tooltip?: string;
};

type QuoteDetailsPanelProps = {
  rateLine: string;
  rows: QuoteDetailRow[];
  isSubscription?: boolean;
  slippageValue?: number;
  onSlippageChange?: (value: SlippageConfigValue) => void | Promise<void>;
  slippageConfig?: SlippageConfigValue;
  exchangeRate?: string | null;
  baseCurrency?: string;
  disabled?: boolean;
};

export default function QuoteDetailsPanel({
  rateLine,
  rows,
  isSubscription = false,
  slippageValue = 0.5,
  onSlippageChange = undefined,
  slippageConfig = undefined,
  exchangeRate = null,
  baseCurrency = 'USD',
  disabled = false,
}: QuoteDetailsPanelProps) {
  const { t } = useLocaleContext();
  const [open, setOpen] = useState(false);
  const [showContent, setShowContent] = useState(true);
  const [dialogOpen, setDialogOpen] = useState(false);
  const [pendingConfig, setPendingConfig] = useState<SlippageConfigValue | null>(null);
  const [submitting, setSubmitting] = useState(false);
  const hasRows = rows.length > 0;

  const handleOpenDialog = useCallback(() => {
    setPendingConfig(slippageConfig || { mode: 'percent', percent: slippageValue });
    setDialogOpen(true);
  }, [slippageValue, slippageConfig]);

  const handleCloseDialog = () => {
    setDialogOpen(false);
    setPendingConfig(null);
  };

  const handleSlippageChange = (value: number) => {
    setPendingConfig((prev) => (prev ? { ...prev, percent: value } : { mode: 'percent', percent: value }));
  };

  const handleConfigChange = (config: SlippageConfigValue) => {
    setPendingConfig(config);
  };

  const handleSubmit = async () => {
    if (!pendingConfig || !onSlippageChange) return;

    setSubmitting(true);
    try {
      const configToSave: SlippageConfigValue = {
        ...pendingConfig,
        ...(baseCurrency ? { base_currency: baseCurrency } : {}),
      };
      await onSlippageChange(configToSave);
      setDialogOpen(false);
      setPendingConfig(null);
    } catch (err) {
      console.error('Failed to update slippage', err);
    } finally {
      setSubmitting(false);
    }
  };

  // Trigger fade effect when rateLine changes
  useEffect(() => {
    if (!rateLine) return undefined;
    setShowContent(false);
    const timer = setTimeout(() => {
      setShowContent(true);
    }, 150);
    return () => clearTimeout(timer);
  }, [rateLine]);

  const renderedRows = useMemo(
    () =>
      rows.map((row) => {
        const isSlippageRow = row.isSlippage && isSubscription && onSlippageChange;
        return (
          <Stack
            key={row.label}
            direction="row"
            sx={{
              alignItems: 'center',
              justifyContent: 'space-between',
              gap: 2,
            }}>
            <Stack direction="row" spacing={0.5} alignItems="center">
              <Typography sx={{ fontSize: '0.75rem', color: 'text.secondary' }}>{row.label}</Typography>
              {row.tooltip && (
                <Tooltip title={row.tooltip} placement="top">
                  <InfoOutlinedIcon sx={{ fontSize: '0.75rem', color: 'text.lighter' }} />
                </Tooltip>
              )}
            </Stack>
            <Stack direction="row" alignItems="center" spacing={0.5}>
              <Typography sx={{ fontSize: '0.75rem', color: 'text.primary' }}>{row.value}</Typography>
              {isSlippageRow && !disabled && (
                <IconButton size="small" onClick={handleOpenDialog} sx={{ p: 0.25 }}>
                  <SettingsIcon sx={{ fontSize: '0.875rem', color: 'text.secondary' }} />
                </IconButton>
              )}
            </Stack>
          </Stack>
        );
      }),
    [rows, isSubscription, onSlippageChange, disabled, handleOpenDialog]
  );

  // For subscriptions with slippage settings, show panel even without rateLine
  // This allows metered subscriptions to configure slippage before first usage
  const showSlippageOnly = !rateLine && isSubscription && onSlippageChange && rows.some((r) => r.isSlippage);

  if (!rateLine && !showSlippageOnly) {
    return null;
  }

  return (
    <>
      <Box sx={{ width: '100%', mt: 0.5 }}>
        <Stack
          direction="row"
          sx={{
            alignItems: 'center',
            justifyContent: 'space-between',
            gap: 1,
          }}>
          {rateLine ? (
            <Fade in={showContent} timeout={300}>
              <Typography sx={{ fontSize: '0.7875rem', color: 'text.lighter' }}>{rateLine}</Typography>
            </Fade>
          ) : (
            <Box /> // Empty placeholder when no rate line
          )}
          {hasRows && (
            <IconButton size="small" onClick={() => setOpen((prev) => !prev)} aria-label={open ? 'collapse' : 'expand'}>
              <ExpandMoreIcon
                sx={{
                  fontSize: '1rem',
                  transition: 'transform 0.2s ease',
                  transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
                }}
              />
            </IconButton>
          )}
        </Stack>
        {hasRows && (
          <Collapse in={open} timeout="auto" unmountOnExit>
            <Fade in={showContent} timeout={300}>
              <Stack
                sx={{
                  mt: 1,
                  p: 1.25,
                  borderRadius: 1,
                  border: '1px solid',
                  borderColor: 'divider',
                  bgcolor: 'action.hover',
                }}
                spacing={1}>
                {renderedRows}
              </Stack>
            </Fade>
          </Collapse>
        )}
      </Box>

      <Dialog open={dialogOpen} onClose={handleCloseDialog} maxWidth="sm" fullWidth>
        <DialogTitle>{t('payment.checkout.quote.slippage.title')}</DialogTitle>
        <DialogContent>
          <SlippageConfig
            value={pendingConfig?.percent ?? slippageValue}
            onChange={handleSlippageChange}
            config={pendingConfig || slippageConfig}
            onConfigChange={handleConfigChange}
            exchangeRate={exchangeRate}
            baseCurrency={baseCurrency}
            disabled={disabled || submitting}
            sx={{ mt: 1 }}
            onCancel={handleCloseDialog}
            onSave={handleSubmit}
          />
        </DialogContent>
      </Dialog>
    </>
  );
}
