import React from 'react';
import { observer } from 'mobx-react-lite';
import { Box } from '@wix/design-system';
import { SetupWidgetState, SetupWidgetStep } from '@wix/bex-core';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { CardContainer } from '../CardContainer';
import { useIsMobile } from '../../hooks/useIsMobile';
import { useIntersectionObserver } from '../../hooks/useIntersectionObserver';
import { SetupWidgetHeader } from './SetupWidgetHeader';
import { SetupStepRow } from './SetupStepRow';
import { SetupStepCard } from './SetupStepCard';
import { SetupStepGroup } from './SetupStepGroup';
import { AllCompleteState } from './AllCompleteState';
import { SetupWidgetSkeleton } from './SetupWidgetSkeleton';

export interface SetupWidgetProps {
  /**
   * A Setup widget state instance created with `useSetupWidget`. The widget
   * owns loading / error / refetch; the state exposes the steps and a public
   * API to change a step's status.
   */
  state: SetupWidgetState;
  /**
   * Inline-expansion content for a step, supplied at render time (the data does
   * not carry it). Returned for the currently-expanded inline step.
   */
  renderStepContent?: (step: SetupWidgetStep) => React.ReactNode;
  /** Fired when a `navigate` step (or its CTA) is activated. */
  onStepClick?: (step: SetupWidgetStep) => void;
  /**
   * Fired when a *completed* step's CTA (or row) is activated — a distinct
   * action from `onStepClick` (mirrors `onCompletedCtaClick` in dashboard-setup,
   * which targets the step's separate `completedCta`).
   */
  onCompletedStepClick?: (step: SetupWidgetStep) => void;
  /**
   * Fired once when a step (or group) scrolls into view — for the consumer to
   * report view telemetry (BI/dealer). The widget itself stays
   * telemetry-agnostic. Click telemetry hooks into `onStepClick` /
   * `onCompletedStepClick`.
   */
  onStepView?: (step: SetupWidgetStep) => void;
  /** Fired when the "all complete" celebratory CTA is clicked. */
  onAllCompleteClick?: () => void;
  /**
   * Replaces the default error UI when the initial load fails. Receives a
   * `retry` callback (re-runs the load) and the thrown `error`. When omitted, a
   * standard error card with a "Try again" retry is shown.
   */
  renderError?: (params: {
    retry: () => void;
    error: unknown;
  }) => React.ReactNode;
  /** Applies a data-hook attribute for tests. */
  dataHook?: string;
}

// Fires `onView` once when the wrapped step scrolls into view. Only mounted
// when the consumer passes `onStepView`, so view tracking adds no DOM/observer
// overhead otherwise.
const StepViewTracker = ({
  stepId,
  onView,
  children,
}: {
  stepId: string;
  onView: () => void;
  children: React.ReactNode;
}) => {
  const { elementRef } = useIntersectionObserver(onView);
  return (
    <div
      ref={elementRef as React.RefObject<HTMLDivElement>}
      data-hook={`setup-step-view-${stepId}`}
    >
      {children}
    </div>
  );
};

const _SetupWidget = ({
  state,
  renderStepContent,
  onStepClick,
  onCompletedStepClick,
  onStepView,
  onAllCompleteClick,
  renderError,
  dataHook,
}: SetupWidgetProps) => {
  const { translate: t } = useWixPatternsContainer();
  const isMobile = useIsMobile();
  const { status } = state._loadTask.status;

  const activateStep = (step: SetupWidgetStep) => {
    // Completed steps fire their own action (never expand) — distinct from the
    // active/navigate `onStepClick`.
    if (step.status === 'completed') {
      onCompletedStepClick?.(step);
      return;
    }
    if (step.expansionMode === 'inline') {
      state._toggleStep(step.id);
    } else {
      onStepClick?.(step);
    }
  };

  // Children of an aggregated group are leaf steps — they never toggle/expand;
  // completed children fire the completed action, the rest navigate.
  const activateChild = (child: SetupWidgetStep) => {
    if (child.status === 'completed') {
      onCompletedStepClick?.(child);
    } else {
      onStepClick?.(child);
    }
  };

  const renderLeaf = (step: SetupWidgetStep, isChild = false) => {
    const expanded =
      !isChild &&
      step.expansionMode === 'inline' &&
      state._expandedStepId === step.id;
    const onActivate = () =>
      isChild ? activateChild(step) : activateStep(step);

    // A single step is focused/highlighted at a time — the expanded step when
    // one is open, otherwise the primary. (Highlighting `primary || expanded`
    // would mark two rows once the user opens a non-primary inline step.)
    const isFocused = !isChild && step.id === state._focusedStepId;

    return isMobile ? (
      <SetupStepCard
        key={step.id}
        step={step}
        isPrimary={isFocused}
        expanded={expanded}
        onActivate={onActivate}
        renderStepContent={renderStepContent}
      />
    ) : (
      <SetupStepRow
        key={step.id}
        step={step}
        isFocused={isFocused}
        expanded={expanded}
        onActivate={onActivate}
        renderStepContent={renderStepContent}
      />
    );
  };

  // All-complete is a distinct success surface with its own card.
  if (status === 'success' && state._isAllComplete) {
    return (
      <AllCompleteState dataHook={dataHook} onCtaClick={onAllCompleteClick} />
    );
  }

  // Built-in loading skeleton, shaped like the widget (desktop card / mobile
  // bare) so there's no layout jump when data resolves.
  if (status === 'idle' || status === 'loading') {
    return <SetupWidgetSkeleton isMobile={isMobile} dataHook={dataHook} />;
  }

  // Consumer-supplied error UI fully replaces the default error card.
  if (status === 'error' && renderError) {
    return (
      <>
        {renderError({
          retry: () => state._retry(),
          error: state._loadTask.errorStatus?.error,
        })}
      </>
    );
  }

  const header = (
    <SetupWidgetHeader
      title={state._title}
      completedCount={state._completedCount}
      totalCount={state._totalCount}
      progressPercentage={state._progressPercentage}
      isMobile={isMobile}
    />
  );

  const list = (
    <Box direction="vertical" gap={isMobile ? 'SP3' : 'SP1'} width="100%">
      {state.steps.map((step) => {
        const node = step.steps?.length ? (
          <SetupStepGroup
            step={step}
            isMobile={isMobile}
            expanded={state._expandedStepId === step.id}
            isPrimary={step.id === state._primaryStepId}
            onToggle={() => state._toggleStep(step.id)}
            renderChild={(child) => renderLeaf(child, true)}
          />
        ) : (
          renderLeaf(step)
        );

        return onStepView ? (
          <StepViewTracker
            key={step.id}
            stepId={step.id}
            onView={() => onStepView(step)}
          >
            {node}
          </StepViewTracker>
        ) : (
          <React.Fragment key={step.id}>{node}</React.Fragment>
        );
      })}
    </Box>
  );

  const body = (
    <>
      {header}
      {list}
    </>
  );

  // Mobile success renders bare — no outer card (matches the mobile design;
  // the consumer composes the surrounding page). Loading / error still flow
  // through CardContainer so the widget owns those states everywhere.
  if (isMobile && status === 'success') {
    return (
      <Box dataHook={dataHook} direction="vertical" gap="SP3" width="100%">
        {body}
      </Box>
    );
  }

  return (
    <CardContainer
      dataHook={dataHook}
      status={status}
      errorState={{
        dataHook: 'error-state',
        title: t('cairo.setupWidget.error.title'),
        subtitle: t('cairo.setupWidget.error.subtitle'),
        action: {
          text: t('cairo.setupWidget.error.cta'),
          onClick: () => state._retry(),
        },
      }}
    >
      <Box direction="vertical" padding="SP6">
        {body}
      </Box>
    </CardContainer>
  );
};

export const SetupWidget = observer(_SetupWidget);
