/**
 * ConfigListDetail — reusable two-pane master/detail layout component.
 *
 * Left pane: scrollable list of config items with active/inactive badges.
 * Active items sort to the top.  Selected item is highlighted.
 * Right pane: renders {@link children} for the selected item, or an empty
 * state message when nothing is selected.
 *
 * Keyboard navigation: ArrowUp / ArrowDown navigate items; Enter selects.
 * On screens narrower than 900 px the list collapses to a Dropdown above
 * the detail pane.
 */

import { useCallback, useEffect, useMemo, useRef } from "react";
import {
  Badge,
  Dropdown,
  MessageBar,
  MessageBarBody,
  Option,
  Skeleton,
  SkeletonItem,
  Text,
  Tooltip,
  tokens,
} from "@fluentui/react-components";
import type { OptionOnSelectData, SelectionEvents } from "@fluentui/react-components";
import { DocumentSearch24Regular } from "@fluentui/react-icons";
import { useConfigStyles } from "./configStyles";

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface ConfigListDetailProps<T extends { name: string }> {
  /** Complete list of config items to display. */
  items: T[];
  /** Predicate that determines whether an item is "active". */
  isActive: (item: T) => boolean;
  /** Currently selected item name, or null when nothing is selected. */
  selectedName: string | null;
  /** Called when the user selects an item by name. */
  onSelect: (name: string) => void;
  /** Whether the items list is still being fetched. */
  loading: boolean;
  /** Error string if the items list failed to load, or null. */
  error: string | null;
  /** Detail pane content for the currently selected item. */
  children: React.ReactNode;
  /**
   * Optional content rendered at the top of the list pane (e.g. a "Create"
   * button).  Visible on all screen sizes above the item list.
   */
  listHeader?: React.ReactNode;
  /**
   * Optional callback to override the badge text for an item.  When omitted
   * the badge shows ``"Active"`` or ``"Inactive"``.
   */
  itemBadgeLabel?: (item: T) => string;
}

/** Number of skeleton placeholder rows shown while loading. */
const SKELETON_COUNT = 5;

/** Maximum characters shown in a list-item name before ellipsis truncation. */
const TOOLTIP_THRESHOLD = 22;

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/**
 * Sort items so active ones appear first, then alphabetically within each
 * group.
 */
function sortItems<T extends { name: string }>(
  items: T[],
  isActive: (item: T) => boolean,
): T[] {
  return [...items].sort((a, b) => {
    const aActive = isActive(a) ? 0 : 1;
    const bActive = isActive(b) ? 0 : 1;
    if (aActive !== bActive) return aActive - bActive;
    return a.name.localeCompare(b.name);
  });
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

/**
 * Two-pane list/detail layout for config tabs.
 *
 * @param props - Component props.
 * @returns JSX element.
 */
export function ConfigListDetail<T extends { name: string }>({
  items,
  isActive,
  selectedName,
  onSelect,
  loading,
  error,
  children,
  listHeader,
  itemBadgeLabel,
}: ConfigListDetailProps<T>): React.JSX.Element {
  const styles = useConfigStyles();

  const sorted = useMemo(() => sortItems(items, isActive), [items, isActive]);

  /** Ref to the currently focused list item for keyboard navigation. */
  const listRef = useRef<HTMLDivElement | null>(null);

  // --------------------------------------------------------------------------
  // Keyboard navigation for the list pane
  // --------------------------------------------------------------------------

  const handleKeyDown = useCallback(
    (event: React.KeyboardEvent<HTMLDivElement>): void => {
      if (sorted.length === 0) return;

      const currentIndex = selectedName
        ? sorted.findIndex((item) => item.name === selectedName)
        : -1;

      if (event.key === "ArrowDown") {
        event.preventDefault();
        const nextIdx = currentIndex < sorted.length - 1 ? currentIndex + 1 : 0;
        const nextItem = sorted[nextIdx];
        if (nextItem) onSelect(nextItem.name);
      } else if (event.key === "ArrowUp") {
        event.preventDefault();
        const prevIdx = currentIndex > 0 ? currentIndex - 1 : sorted.length - 1;
        const prevItem = sorted[prevIdx];
        if (prevItem) onSelect(prevItem.name);
      }
    },
    [sorted, selectedName, onSelect],
  );

  // Scroll selected item into view when selection changes.
  useEffect(() => {
    if (!listRef.current || !selectedName) return;
    const el = listRef.current.querySelector<HTMLElement>(
      `[data-name="${CSS.escape(selectedName)}"]`,
    );
    el?.scrollIntoView({ block: "nearest" });
  }, [selectedName]);

  // --------------------------------------------------------------------------
  // Dropdown handler (responsive collapse)
  // --------------------------------------------------------------------------

  const handleDropdownSelect = useCallback(
    (_ev: SelectionEvents, data: OptionOnSelectData): void => {
      if (data.optionValue) onSelect(data.optionValue);
    },
    [onSelect],
  );

  // --------------------------------------------------------------------------
  // Loading / error states
  // --------------------------------------------------------------------------

  if (loading) {
    return (
      <Skeleton aria-label="Loading configuration items…">
        {Array.from({ length: SKELETON_COUNT }, (_, i) => (
          <SkeletonItem key={i} size={40} style={{ marginBottom: 4 }} />
        ))}
      </Skeleton>
    );
  }

  if (error) {
    return (
      <MessageBar intent="error">
        <MessageBarBody>{error}</MessageBarBody>
      </MessageBar>
    );
  }

  // --------------------------------------------------------------------------
  // Empty items list
  // --------------------------------------------------------------------------

  if (sorted.length === 0) {
    return (
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          justifyContent: "center",
          gap: tokens.spacingVerticalM,
          padding: `${tokens.spacingVerticalXXL} ${tokens.spacingHorizontalL}`,
          color: tokens.colorNeutralForeground3,
          textAlign: "center",
        }}
      >
        <DocumentSearch24Regular
          style={{ fontSize: 48, color: tokens.colorNeutralForeground3 }}
          aria-hidden
        />
        <Text size={400}>No items found.</Text>
      </div>
    );
  }

  // --------------------------------------------------------------------------
  // Full layout
  // --------------------------------------------------------------------------

  return (
    <div className={styles.listDetailRoot}>
      {/* ── Left pane: full-width on narrow screens → Dropdown ── */}
      <div
        className={styles.listPane}
        role="listbox"
        aria-label="Configuration items"
        tabIndex={0}
        onKeyDown={handleKeyDown}
        ref={listRef}
      >
        {/* Optional header content (e.g. a Create button) */}
        {listHeader !== undefined && (
          <div style={{ marginBottom: tokens.spacingVerticalS }}>{listHeader}</div>
        )}
        {/* Responsive dropdown (visible only on narrow screens via CSS) */}
        <div
          style={{
            display: "none",
          }}
          className="bangui-list-dropdown"
        >
          <Dropdown
            aria-label="Select configuration item"
            value={selectedName ?? ""}
            selectedOptions={selectedName ? [selectedName] : []}
            onOptionSelect={handleDropdownSelect}
            style={{ width: "100%", marginBottom: tokens.spacingVerticalS }}
          >
            {sorted.map((item) => (
              <Option key={item.name} value={item.name} text={item.name}>
                {item.name}
                {isActive(item) ? " (Active)" : " (Inactive)"}
              </Option>
            ))}
          </Dropdown>
        </div>

        {/* Item list (hidden on narrow screens via CSS) */}
        <div className="bangui-list-items">
          {sorted.map((item) => {
            const active = isActive(item);
            const selected = item.name === selectedName;
            const needsTooltip = item.name.length > TOOLTIP_THRESHOLD;
            const badgeText = itemBadgeLabel
              ? itemBadgeLabel(item)
              : active
                ? "Active"
                : "Inactive";

            const itemEl = (
              <div
                key={item.name}
                data-name={item.name}
                role="option"
                aria-selected={selected}
                tabIndex={-1}
                className={[
                  styles.listItem,
                  selected ? styles.listItemSelected : "",
                ]
                  .filter(Boolean)
                  .join(" ")}
                onClick={() => {
                  onSelect(item.name);
                }}
                onKeyDown={(e) => {
                  if (e.key === "Enter") onSelect(item.name);
                }}
              >
                <Text
                  size={300}
                  style={{
                    overflow: "hidden",
                    textOverflow: "ellipsis",
                    whiteSpace: "nowrap",
                    flex: 1,
                    marginRight: tokens.spacingHorizontalXS,
                  }}
                >
                  {item.name}
                </Text>
                <Badge
                  appearance={active ? "filled" : "outline"}
                  color={active ? "success" : "informative"}
                  size="small"
                  style={{ flexShrink: 0 }}
                >
                  {badgeText}
                </Badge>
              </div>
            );

            return needsTooltip ? (
              <Tooltip key={item.name} content={item.name} relationship="label">
                {itemEl}
              </Tooltip>
            ) : (
              itemEl
            );
          })}
        </div>
      </div>

      {/* ── Right pane: detail content ── */}
      <div className={styles.detailPane}>
        {selectedName === null ? (
          <div
            style={{
              display: "flex",
              flexDirection: "column",
              alignItems: "center",
              justifyContent: "center",
              gap: tokens.spacingVerticalM,
              padding: `${tokens.spacingVerticalXXL} ${tokens.spacingHorizontalL}`,
              color: tokens.colorNeutralForeground3,
              textAlign: "center",
            }}
          >
            <DocumentSearch24Regular
              style={{ fontSize: 48, color: tokens.colorNeutralForeground3 }}
              aria-hidden
            />
            <Text size={400}>Select an item from the list.</Text>
          </div>
        ) : (
          children
        )}
      </div>
    </div>
  );
}
