import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useAtomValue } from 'jotai';
import { Box, Icon, IconButton, Icons } from 'folds';
import {
  curtainPinnedByTabAtom,
  mobileHorseshoeActiveAtom,
  mobilePagerCurtainAtom,
} from '../../state/mobilePagerHeader';
import { Segment } from '../stream-header/Segment';
import { INLINE_FORM_ID } from '../stream-header/StreamHeader';
import * as streamHeaderCss from '../stream-header/StreamHeader.css';
import type { MobilePagerTab } from './MobilePagerPaneContext';
import * as css from './style.css';

// Positive z-index applied to the static pager header when any
// horseshoe sheet is geometrically active (drag in flight or sheet
// open). Any positive value beats the strip's `z-index: auto`
// stacking context in pagerRoot, so `z: 1` is sufficient; the constant
// just makes the intent explicit at the call site.
const PAGER_HEADER_ELEVATED_Z = 1;

// The pager's tab union — imported, not re-declared, so the
// `pinnedByTab[activeTab]` read below stays type-aligned with the
// per-tab atoms keyed by StreamHeader's `pinKey`.
type Tab = MobilePagerTab;

type MobileTabsPagerHeaderProps = {
  showBots: boolean;
  // Active tab name resolved by the parent pager from the URL. We
  // accept it as a prop rather than re-running `useMatch` here — the
  // pager already knows the answer and passing it down keeps the
  // segment highlight in lock-step with the strip's visual position
  // (one source of truth = `urlActiveIdx`).
  activeTab: Tab;
  onSelectDirect: () => void;
  onSelectChannels: () => void;
  onSelectBots: () => void;
};

// Static shared tabs row painted at the top of MobileTabsPager. Lives
// outside the swipe strip so it doesn't translate with the panes —
// addresses the user-visible regression where each pane's identical
// tabs row sliding underneath felt like "the header is moving" even
// though the segments matched at every pixel.
//
// Reuses `stream-header/StreamHeader.css.ts` classes (`tabsRow`,
// `tabsCluster`, `iconsCluster`) so the layout, padding, and segment
// styling stay identical to the per-pane tabs row that sits hidden
// underneath. The only structural difference is the surrounding
// `pagerStaticHeader` wrapper which positions this row absolute at
// the top of the pager and reserves the status-bar safe-area inset.
//
// Segment clicks call the pager's commit callbacks (so the swipe
// animation uses the same pendingTargetIdx path as a finger swipe).
// Action icons read `mobilePagerCurtainAtom` — the active pane's
// StreamHeader writes its curtain controls there, so Plus/Search/X
// drive whichever curtain is currently visible.
//
// ARIA: action icons mirror the original in-pane buttons'
// `aria-controls` / `aria-expanded` / `aria-haspopup` relationship to
// the form region (`#stream-header-inline-form`). When `iconsDisabled`
// (atom not yet populated on initial mount) the buttons report
// `aria-disabled` so assistive tech announces the unavailable state
// instead of silently failing on activation.
export function MobileTabsPagerHeader({
  showBots,
  activeTab,
  onSelectDirect,
  onSelectChannels,
  onSelectBots,
}: MobileTabsPagerHeaderProps) {
  const { t } = useTranslation();

  const curtainControls = useAtomValue(mobilePagerCurtainAtom);
  const isFormActive = curtainControls?.isFormActive ?? false;
  const openSearch = useCallback(() => curtainControls?.openSearch(), [curtainControls]);
  const closeForm = useCallback(() => curtainControls?.closeForm(), [curtainControls]);
  const iconsDisabled = curtainControls === null;
  // Tab-specific create action (Channels publishes «create channel» /
  // «create community»). When null (Direct) NO Plus renders — new-chat
  // is gone and people are found through search. `primaryAction.onClick`
  // is already stable (memoised by the publishing pane), so we wire it
  // directly into onClick without re-wrapping in another useCallback.
  const primaryAction = curtainControls?.primaryAction ?? null;

  // The static header does NOT translate to follow the curtain. It
  // stays put; the curtain physically rises ABOVE it via z-stack — see
  // the «curtain-overlay invariants» comment in style.css.ts on
  // pagerStaticHeader for the bg / z-order contract.
  //
  // Z-elevation while a horseshoe sheet is GEOMETRICALLY active: the
  // MobileSettings / ChannelsWorkspace container paints
  // `VOJO_HORSESHOE_VOID_COLOR` (= #000 in dark theme) across the
  // entire pane to drive the carve cut-out the moment `expandedPx > 0`.
  // Without elevation that void bleeds up through the transparent
  // strip-stack into the safe-top + tabsRow zone, turning the system-
  // tray strip + tabs black. Bumping the static header into a positive
  // z-index puts it ABOVE the strip's stacking context (positive z
  // beats z:auto stacking contexts per CSS painting order), covering
  // the void in its own y-band with SurfaceVariant bg + visible tabs.
  //
  // The atom tracks the GEOMETRIC signal (`expandedPx > 0`), not the
  // sheet-open atoms, so elevation lands on the FIRST frame of drag —
  // not 80 px later when the user crosses the commit threshold. The
  // horseshoes' appBody flips to opaque in lockstep (same signal),
  // containing the void to the bottom carve everywhere below the
  // static header.
  //
  // Pinned-overrides-elevation: when the active pane's curtain is
  // pinned the curtain itself contains the void — it covers everything
  // from `y = safe-top` downward inside the strip's stacking context,
  // and the opaque appBody (also flipped on `horseshoeActive`) covers
  // the safe-top band above the curtain. Re-elevating the static
  // header in that state would visibly «slice» the pinned curtain in
  // the safe-top + tabsRow band, popping tabs back over what the user
  // explicitly pulled up to cover. So we suppress elevation whenever
  // the active tab's pin is set — preserves the «pinned hides tabs»
  // invariant across sheet open/drag.
  //
  // The curtain pin gesture is suppressed while either sheet is open
  // (see `StreamHeader.gestureDisabled`), so this elevation never
  // races with a pin-in-progress drag.
  const horseshoeActive = useAtomValue(mobileHorseshoeActiveAtom);
  const pinnedByTab = useAtomValue(curtainPinnedByTabAtom);
  const activePinned = !!pinnedByTab[activeTab];
  const elevated = horseshoeActive && !activePinned;

  return (
    <div
      className={css.pagerStaticHeader}
      style={elevated ? { zIndex: PAGER_HEADER_ELEVATED_Z } : undefined}
    >
      <div className={streamHeaderCss.tabsRow}>
        <div className={streamHeaderCss.tabsCluster}>
          <Segment
            active={activeTab === 'direct'}
            label={t('Direct.segment_dm')}
            onClick={onSelectDirect}
          />
          <Segment
            active={activeTab === 'channels'}
            label={t('Direct.segment_channels')}
            onClick={onSelectChannels}
          />
          {showBots && (
            <Segment
              active={activeTab === 'bots'}
              label={t('Direct.segment_bots')}
              onClick={onSelectBots}
            />
          )}
        </div>
        <Box grow="Yes" />
        {isFormActive ? (
          <IconButton
            variant="SurfaceVariant"
            fill="None"
            size="400"
            radii="Pill"
            onClick={closeForm}
            aria-label={t('Direct.close')}
            aria-controls={INLINE_FORM_ID}
            aria-expanded
            disabled={iconsDisabled}
          >
            <Icon size="100" src={Icons.Cross} />
          </IconButton>
        ) : (
          <div className={streamHeaderCss.iconsCluster}>
            {/* Default «new chat» Plus is gone — people are found through
                search. Only the tab's `primaryAction` (Channels'
                create-channel / create-community) renders a Plus; it
                opens a portal Modal dialog, so there's nothing in-subtree
                to point `aria-controls` at. */}
            {primaryAction && (
              <IconButton
                variant="SurfaceVariant"
                fill="None"
                size="400"
                radii="Pill"
                onClick={primaryAction.onClick}
                aria-label={primaryAction.label}
                aria-expanded={false}
                aria-haspopup="dialog"
                disabled={iconsDisabled}
              >
                <Icon size="100" src={primaryAction.iconSrc} />
              </IconButton>
            )}
            <IconButton
              variant="SurfaceVariant"
              fill="None"
              size="400"
              radii="Pill"
              onClick={openSearch}
              aria-label={t('Search.search')}
              aria-controls={INLINE_FORM_ID}
              aria-expanded={false}
              aria-haspopup="dialog"
              disabled={iconsDisabled}
            >
              <Icon size="100" src={Icons.Search} />
            </IconButton>
          </div>
        )}
      </div>
    </div>
  );
}
