import * as React from "react";
import { RefreshCw, Search, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { Input } from "@/components/ui/input";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { KanbanColumn } from "@/components/ui/kanban-column";
import type { KanbanColumnStage } from "@/components/ui/kanban-column";
import type { OpportunityCardProps } from "@/components/ui/opportunity-card";
import { pipelinePrimaryColor } from "@/lib/pipeline-colors";

/**
 * PipelineBoard — WealthX DS (L5 Board)
 *
 * Full Pipeline / Loan CRM kanban board.
 * Renders a horizontal list of KanbanColumns with a toolbar (search + column filters).
 *
 * **Does NOT include:**
 * - Drag-and-drop (react-dnd) — handled by the app's DndProvider + KanbanColumn wiring.
 * - Data fetching — the app supplies `columns` with pre-loaded opportunities.
 * - Modals (edit column, delete, change priority, put on hold) — opened by the app.
 *
 * ### Layer: L5 Board
 * ```
 * PipelineBoard (L5)
 *   └── KanbanColumn (L4)  ×N
 *         └── OpportunityCard (L3)  ×N
 *               └── TaskCheckItem (L2)  ×N
 * ```
 */

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

export interface PipelineBoardColumn {
  /** Unique column key (used as React key — may differ from stage.id). */
  key: string;
  stage: KanbanColumnStage;
  opportunities: OpportunityCardProps[];
  /**
   * When set, each card in this column shows a "Send Loan Application Request"
   * button. Intended for the Leads stage only — cards there have no tasks yet.
   */
  onSendLoanApplication?: (opportunityId: string) => void;
  /** DnD index (-1 for High Priority fixed column). */
  columnIndex?: number;
  /** Whether this column is being dragged (controlled by app DnD). */
  isDragging?: boolean;
  /** Whether a card is hovering over this column (controlled by app DnD). */
  isDropTarget?: boolean;
  /** Whether this is a fixed/system column (no Delete in menu). */
  isDefault?: boolean;
  /** When true, every card in this column renders in on-hold mode. */
  isOnHold?: boolean;
  /**
   * When true, this column is rendered in a fixed left section and does not
   * scroll horizontally with the rest of the board. Use for the High Priority
   * column, which must always be visible.
   */
  isPinned?: boolean;
  isLoading?: boolean;
  isLoadingMore?: boolean;
  hasMore?: boolean;
  loaderRef?: React.Ref<HTMLDivElement>;
  /**
   * When provided, renders a `+` icon button in the column header.
   * Intended for the Leads column — opens the Add Lead flow.
   */
  onAddLead?: () => void;
}

export interface PipelineBoardProps {
  // ── Data ─────────────────────────────────────────────────────
  columns: PipelineBoardColumn[];

  // ── Toolbar ──────────────────────────────────────────────────
  /** Current keyword search value (controlled). */
  searchValue?: string;
  onSearchChange?: (value: string) => void;
  /**
   * Column filter chips. Each item is a label shown as a chip.
   * Pass `"View All"` as a special value to show/select all columns.
   */
  filterOptions?: string[];
  activeFilters?: string[];
  onFilterChange?: (filter: string) => void;

  // ── Column callbacks ─────────────────────────────────────────
  onEditColumn?: (stageId: string) => void;
  onDeleteColumn?: (stageId: string) => void;
  onRefresh?: () => void;

  // ── Card callbacks ───────────────────────────────────────────
  /**
   * Fires when a card is dragged from one column and dropped into another.
   * The app is responsible for updating `columns` accordingly.
   */
  onMoveCard?: (cardId: string, toColumnKey: string) => void;
  /** Fires when clicking the non-interactive card body. */
  onCardClick?: (opportunityId: string) => void;
  onTaskToggle?: (opportunityId: string, taskId: string) => void;
  onMarkAsDone?: (opportunityId: string) => void;
  onMoveToNextStage?: (opportunityId: string) => void;
  onViewDetails?: (opportunityId: string) => void;
  onChangePriority?: (opportunityId: string) => void;
  onPutOnHold?: (opportunityId: string) => void;
  onPlaceBack?: (opportunityId: string) => void;
  onDeleteOpportunity?: (opportunityId: string) => void;
  onSendToAI?: (opp: OpportunityCardProps) => void;
  /** Fires when a broker activates/re-syncs a CRM target on a card (BUILD-2228). */
  onSyncCrmTarget?: (opportunityId: string, targetId: string) => void;
  submittingOpportunityId?: string | null;

  className?: string;
}

// ---------------------------------------------------------------------------
// Toolbar
// ---------------------------------------------------------------------------

interface ToolbarProps {
  searchValue: string;
  onSearchChange: (v: string) => void;
  filterOptions: string[];
  activeFilters: string[];
  onFilterChange: (f: string) => void;
  onRefresh?: () => void;
}

function Toolbar({
  searchValue,
  onSearchChange,
  filterOptions,
  activeFilters,
  onFilterChange,
  onRefresh,
}: ToolbarProps) {
  return (
    <div className="flex flex-wrap items-center gap-3 border-b border-border bg-background px-4 py-3">
      {/* Search */}
      <div className="relative w-56 shrink-0">
        <Search className="absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" />
        <Input
          placeholder="Search opportunities…"
          value={searchValue}
          onChange={(e) => onSearchChange(e.target.value)}
          className="h-8 pl-8 text-sm"
        />
        {searchValue && (
          <Button
            type="button"
            variant="ghost"
            size="icon"
            onClick={() => onSearchChange("")}
            className="absolute right-2 top-1/2 size-6 -translate-y-1/2 text-muted-foreground hover:text-foreground"
            aria-label="Clear search"
          >
            <X className="size-3.5" />
          </Button>
        )}
      </div>

      {/* Column filter toggle group */}
      {filterOptions.length > 0 && (
        <ToggleGroup
          type="multiple"
          variant="outline"
          size="sm"
          spacing={1.5}
          value={activeFilters}
          onValueChange={(newValues) => {
            const toggled =
              newValues.find((v) => !activeFilters.includes(v)) ??
              activeFilters.find((v) => !newValues.includes(v));
            if (toggled) onFilterChange(toggled);
          }}
        >
          {filterOptions.map((option) => (
            <ToggleGroupItem key={option} value={option}>
              {option}
            </ToggleGroupItem>
          ))}
        </ToggleGroup>
      )}

      {/* Refresh */}
      {onRefresh && (
        <Button
          type="button"
          variant="ghost"
          size="icon"
          onClick={onRefresh}
          className="ml-auto text-muted-foreground hover:text-foreground"
          aria-label="Refresh board"
        >
          <RefreshCw className="size-4" />
        </Button>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// PipelineBoard
// ---------------------------------------------------------------------------

export function PipelineBoard({
  columns,
  searchValue = "",
  onSearchChange,
  filterOptions = [],
  activeFilters = [],
  onFilterChange,
  onRefresh,
  onEditColumn,
  onDeleteColumn,
  onMoveCard,
  onCardClick,
  onTaskToggle,
  onMarkAsDone,
  onMoveToNextStage,
  onViewDetails,
  onChangePriority,
  onPutOnHold,
  onPlaceBack,
  onDeleteOpportunity,
  onSendToAI,
  onSyncCrmTarget,
  submittingOpportunityId,
  className,
}: PipelineBoardProps) {
  const hasToolbar =
    onSearchChange || (filterOptions.length > 0 && onFilterChange);

  const pinnedCols = columns.filter((c) => c.isPinned);
  const scrollableCols = columns.filter((c) => !c.isPinned);

  // Columns without a custom accentColor get primary color with descending
  // opacity — matching PipelineChart's scheme via the shared utility.
  const noAccentCols = scrollableCols.filter((c) => !c.stage.accentColor);
  const noAccentCount = noAccentCols.length;
  const computedAccents = new Map<string, string>(
    noAccentCols.map((col, i) => [
      col.key,
      pipelinePrimaryColor(i, noAccentCount),
    ]),
  );

  const renderColumn = (col: PipelineBoardColumn) => {
    const resolvedStage = computedAccents.has(col.key)
      ? { ...col.stage, accentColor: computedAccents.get(col.key) }
      : col.stage;
    return (
      <KanbanColumn
        key={col.key}
        stage={resolvedStage}
        opportunities={col.opportunities}
        isDragging={col.isDragging}
        isDropTarget={col.isDropTarget}
        isDefault={col.isDefault}
        isLoading={col.isLoading}
        isLoadingMore={col.isLoadingMore}
        hasMore={col.hasMore}
        loaderRef={col.loaderRef}
        onEditColumn={
          !col.isPinned && onEditColumn
            ? () => onEditColumn(col.stage.id)
            : undefined
        }
        onDeleteColumn={
          onDeleteColumn && !col.isDefault && !col.isPinned
            ? () => onDeleteColumn(col.stage.id)
            : undefined
        }
        onCardDrop={
          onMoveCard ? (cardId) => onMoveCard(cardId, col.key) : undefined
        }
        onCardClick={onCardClick}
        onTaskToggle={onTaskToggle}
        onMarkAsDone={onMarkAsDone}
        onMoveToNextStage={onMoveToNextStage}
        onSendLoanApplication={col.onSendLoanApplication}
        onViewDetails={onViewDetails}
        onChangePriority={onChangePriority}
        isOnHoldColumn={col.isOnHold}
        onPutOnHold={onPutOnHold}
        onPlaceBack={onPlaceBack}
        onDeleteOpportunity={onDeleteOpportunity}
        onSendToAI={onSendToAI}
        onSyncCrmTarget={onSyncCrmTarget}
        onAddLead={col.onAddLead}
        submittingOpportunityId={submittingOpportunityId}
      />
    );
  };

  return (
    <div
      className={cn("flex h-full flex-col bg-muted/20", className)}
      data-slot="pipeline-board"
    >
      {/* ── Toolbar ── */}
      {hasToolbar && (
        <Toolbar
          searchValue={searchValue}
          onSearchChange={onSearchChange ?? (() => {})}
          filterOptions={filterOptions}
          activeFilters={activeFilters}
          onFilterChange={onFilterChange ?? (() => {})}
          onRefresh={onRefresh}
        />
      )}

      {/* ── Board area ── */}
      <div className="flex flex-1 overflow-hidden">
        {/* Pinned columns — always visible, do not scroll */}
        {pinnedCols.length > 0 && (
          <div className="flex shrink-0 gap-3 border-r border-border p-4">
            {pinnedCols.map(renderColumn)}
          </div>
        )}

        {/* Scrollable columns */}
        <div className="flex flex-1 gap-3 overflow-x-auto p-4">
          {scrollableCols.map(renderColumn)}

          {columns.length === 0 && (
            <div className="flex flex-1 items-center justify-center">
              <p className="text-sm text-muted-foreground">
                No columns to display.
              </p>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
