import { useState, useEffect, useRef, useCallback, useMemo } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { motion, AnimatePresence } from "framer-motion";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger,
} from "@/components/ui/dialog";
import {
  Sheet, SheetContent, SheetHeader, SheetTitle,
} from "@/components/ui/sheet";
import {
  Timer, Gavel, Users, User, TrendingUp, Zap, ChevronUp, ChevronDown,
  Leaf, Scale, Info, BarChart3, Pause, Play, CheckCircle, XCircle,
  TrendingDown, Package, Shield, Eye, AlertTriangle, Crown, Droplets, Trophy,
} from "lucide-react";
import { SizeGradePills } from "@/components/size-grades/SizeGradePills";
import { BatchMediaGallery } from "@/components/lots/BatchMediaGallery";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/contexts/AuthContext";
import { useToast } from "@/hooks/use-toast";
import { fetchLotMediaMap, type LotMediaItem } from "@/lib/lot-media";
import { getLotTypeLabel } from "@/lib/lot-type-label";
import { resolveTopBidResolution } from "@/lib/auction-tie";
import { serverNow } from "@/lib/server-time";
import { toggleBatchPause, startBatchCooling } from "@/lib/batch-pause";
import { useBatchTimer } from "@/lib/use-batch-timer";
import { formatLotLabel } from "@/lib/batch-status";
import { useTimerHeartbeat } from "@/lib/use-timer-heartbeat";
import { CoolingScreen } from "@/components/auction/CoolingScreen";

import { useAdminSettings } from "@/hooks/use-admin-settings";
import { useApprovalGate } from "@/hooks/use-approval-gate";
import { buildPerSizeGradingRows, sortSizeGradesDesc, sumGradingTotals, labelWithPct } from "@/lib/size-grades";

type BatchDetailsState = {
  quality: { label: string; value: string }[];
  grades: any[];
  media: LotMediaItem[];
  gl: string;
  moisture: string;
};

const emptyBatchDetails: BatchDetailsState = {
  quality: [],
  grades: [],
  media: [],
  gl: "—",
  moisture: "—",
};

const formatNumericValue = (value: number | string | null | undefined) => {
  if (value === null || value === undefined || value === "") return "—";
  return Number(value).toLocaleString("en-IN", { maximumFractionDigits: 2 });
};

const formatPercentage = (value: number | string | null | undefined) => {
  if (value === null || value === undefined || value === "") return "—";
  return `${formatNumericValue(value)}%`;
};

// ─── Shared Components ───

// Resolve a banner background from the batch's stored color (solid, no gradient).
// Falls back to the design-system primary color.
const BATCH_COLOR_SOLIDS: Record<string, string> = {
  green: "hsl(135 70% 28%)",
  avg_green: "hsl(88 55% 35%)",
  seconds: "hsl(40 80% 38%)",
};
// Light tints for queued/catalog cards — same hue family but pastel.
const BATCH_COLOR_LIGHT_TINTS: Record<string, string> = {
  green: "hsl(135 55% 94%)",
  avg_green: "hsl(88 50% 94%)",
  seconds: "hsl(40 75% 93%)",
};
const resolveBatchBackground = (batch: any) => {
  // Artificial colour: do NOT change colour — fall through to the natural batch_color (or default).
  return BATCH_COLOR_SOLIDS[batch?.batch_color] || "hsl(var(--primary))";
};
const resolveBatchLightTint = (batch: any): string | undefined => {
  // Artificial coloured lots stay neutral (no tint).
  if (batch?.is_artificial_coloured) return undefined;
  return BATCH_COLOR_LIGHT_TINTS[batch?.batch_color];
};

// Returns the user-facing lot type label.
const resolveLotType = (batch: any) => {
  let label = getLotTypeLabel(batch);
  if (batch?.is_artificial_coloured && !batch?.is_seeds) label += " (Artificial Coloured)";
  return label;
};
const resolveLotTypeShort = (batch: any) => {
  if (batch?.is_seeds) return "Seed";
  if (batch?.is_single_graded) return "Graded";
  return getLotTypeLabel(batch);
};

const LiveBanner = ({ batch, currentBid, seconds, bidCount, isPaused, isCooling, coolingSeconds, uniqueBidders, isOutbid, isLeading, bidFlash, gl, moisture }: any) => {
  const lotTypeShort = resolveLotTypeShort(batch);
  const statusRing = isLeading
    ? "ring-4 ring-emerald-400/80 shadow-[0_0_24px_rgba(16,185,129,0.55)]"
    : isOutbid
      ? "ring-4 ring-destructive/70 shadow-[0_0_24px_rgba(239,68,68,0.55)]"
      : "";
  return (
    <motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }}
      className={`relative rounded-lg px-4 py-2.5 sm:px-5 sm:py-3 text-primary-foreground overflow-hidden ${statusRing}`}
      style={{ background: resolveBatchBackground(batch) }}>
      <div className="relative">
        {/* Top row: Lot # · Qty · type chip */}
        <div className="flex items-center gap-2 mb-1.5 flex-wrap justify-between">
          <span className="font-display text-lg sm:text-xl font-bold flex items-center gap-2 flex-wrap">
            <span>{batch.lot_seq != null ? `Lot #${batch.lot_seq}` : `Lot ${batch.lot_number}`}</span>
            <span className="font-display text-lg sm:text-xl font-bold opacity-90">· Qty: {Number(batch.quantity_kg).toLocaleString("en-IN")} kg</span>
            <span className="font-sans text-[10px] uppercase tracking-wider px-2 py-0.5 rounded-full bg-primary-foreground/15 border border-primary-foreground/25 font-semibold">
              {lotTypeShort}
            </span>
            {batch?.is_artificial_coloured && (
              <span className="font-sans text-[10px] uppercase tracking-wider px-2 py-0.5 rounded-full bg-amber-500/25 border border-amber-200/50 text-amber-50 font-semibold">
                Artificial Coloured
              </span>
            )}
          </span>
          <div className="flex items-center gap-2">
            {isOutbid && (
              <Badge className="bg-destructive text-destructive-foreground border-0 text-xs gap-1">OUTBID</Badge>
            )}
            {isLeading && (
              <Badge className="bg-emerald-500 text-white border-0 text-xs gap-1">★ LEADING</Badge>
            )}
            {isCooling ? (
              <Badge className="bg-warning text-warning-foreground border-0 text-xs gap-1 px-2.5 py-1 animate-pulse"><Timer className="h-3 w-3" /> COOLING</Badge>
            ) : isPaused ? (
              <Badge className="bg-warning text-warning-foreground border-0 text-xs gap-1 px-2.5 py-1"><Pause className="h-3 w-3" /> PAUSED</Badge>
            ) : (
              <Badge className="bg-live text-live-foreground border-0 text-xs gap-1 px-2.5 py-1 animate-pulse-live"><Zap className="h-3 w-3" /> LIVE</Badge>
            )}
          </div>
        </div>

        {/* Hero: Current Bid + Timer */}
        <div className="flex items-end justify-between gap-4">
          <div className="relative min-w-0">
            <p className="text-[10px] font-sans opacity-70 uppercase tracking-wider">Current Bid</p>
            {/* #2 Enlarged bid price */}
            <motion.p key={currentBid} initial={{ scale: 1.2 }} animate={{ scale: 1 }} className="font-display text-4xl sm:text-5xl font-bold leading-tight">
              ₹{currentBid.toLocaleString("en-IN")}
            </motion.p>
            {/* #4 Bid flash animation */}
            <AnimatePresence>
              {bidFlash !== null && bidFlash !== undefined && (
                <motion.span
                  key={`flash-${Date.now()}`}
                  initial={{ opacity: 1, y: 0 }}
                  animate={{ opacity: 0, y: -30 }}
                  exit={{ opacity: 0 }}
                  transition={{ duration: 0.8 }}
                  className="absolute -top-3 left-0 text-sm font-bold text-live font-sans"
                >
                  +₹{bidFlash}
                </motion.span>
              )}
            </AnimatePresence>
          </div>
          <div className="text-right shrink-0">
            <p className="text-[10px] font-sans opacity-70 uppercase tracking-wider flex items-center gap-1 justify-end">
              <Timer className="h-3 w-3" /> {isCooling ? "Cooling" : "Time Left"}
            </p>
            {isCooling ? (
              <motion.p key={`cool-${coolingSeconds}`} initial={{ scale: 1.1 }} animate={{ scale: 1 }}
                className="font-display text-3xl sm:text-5xl font-bold tabular-nums leading-tight text-warning">
                00:{String(Math.max(0, coolingSeconds)).padStart(2, "0")}
              </motion.p>
            ) : isPaused ? (
              <p className="font-display text-3xl sm:text-5xl font-bold tabular-nums text-warning leading-tight">--:--</p>
            ) : (
              <motion.p key={seconds} initial={{ scale: 1.1 }} animate={{ scale: 1 }}
                className={`font-display text-3xl sm:text-5xl font-bold tabular-nums leading-tight ${seconds <= 5 ? "text-live" : ""}`}>
                00:{String(Math.max(0, seconds)).padStart(2, "0")}
              </motion.p>
            )}
          </div>
        </div>

        {!isPaused && !isCooling && (
          <motion.div className="mt-2 h-1 rounded-full bg-primary-foreground/20 overflow-hidden">
            <motion.div className="h-full rounded-full"
              style={{ background: seconds <= 5 ? "hsl(0, 75%, 50%)" : "hsl(68, 40%, 48%)" }}
              animate={{ width: `${(Math.max(0, seconds) / 15) * 100}%` }} transition={{ duration: 0.5 }} />
          </motion.div>
        )}

        {/* Secondary: Bags · Base · g/L · Moisture · (Seconds % if seed) */}
        <div className={`grid ${batch.is_seeds ? "grid-cols-6" : "grid-cols-4"} gap-1.5 mt-2 pt-2 border-t border-primary-foreground/15`}>
          {([
            { label: "Bags", value: batch.number_of_bags != null ? Number(batch.number_of_bags).toLocaleString("en-IN") : "—" },
            { label: "Base", value: `₹${Number(batch.base_price).toLocaleString("en-IN")}` },
            { label: "LTR/WT", value: gl ?? "—" },
            { label: "Moisture", value: moisture ?? "—" },
            ...(batch.is_seeds ? [
              { label: "Husk", value: (batch as any).husk_percent != null ? `${Number((batch as any).husk_percent)}%` : "—" },
              { label: "Cardamom", value: (batch as any).cardamom_percent != null ? `${Number((batch as any).cardamom_percent)}%` : "—" },
            ] : []),
          ] as { label: string; value: any }[]).map((m) => (
            <div key={m.label} className="text-center min-w-0">
              <p className={`${batch.is_seeds ? "text-[8px] sm:text-[9px]" : "text-[9px] sm:text-[10px]"} font-sans opacity-60 uppercase tracking-wider truncate`}>{m.label}</p>
              <p className={`font-display ${batch.is_seeds ? "text-xs sm:text-base" : "text-sm sm:text-xl"} font-semibold whitespace-nowrap leading-tight`}>
                {m.value}
              </p>
            </div>
          ))}
        </div>

        <div className="flex items-center gap-4 mt-1.5 text-[10px] font-sans opacity-70">
          <span className="flex items-center gap-1"><Users className="h-3 w-3" /> {uniqueBidders ?? 0} bidders</span>
          <span className="flex items-center gap-1"><TrendingUp className="h-3 w-3" /> {bidCount} bids</span>
        </div>
      </div>
    </motion.div>
  );
};

const BidHistory = ({ bidHistory, bidCount, userId, uniqueBidders }: any) => {
  const getBidderName = (bid: any) => {
    if (bid.user_id === userId) return "You";
    return bid.profiles?.firm_name || bid.profiles?.full_name || "Trader";
  };
  return (
    <Card>
      <CardHeader className="pb-2 px-3 sm:px-5 pt-3 sm:pt-4">
        <CardTitle className="font-display text-sm sm:text-base flex items-center gap-2">
          Bid History <Badge variant="outline" className="text-[10px]">{bidCount} bids</Badge> <Badge variant="outline" className="text-[10px]">{uniqueBidders ?? 0} bidders</Badge>
        </CardTitle>
      </CardHeader>
      <CardContent className="p-0 max-h-60 overflow-y-auto">
        <AnimatePresence initial={false}>
          {bidHistory.map((bid: any, i: number) => {
            const isYou = bid.user_id === userId;
            const isTop = i === 0;
            return (
              <motion.div key={bid.id} initial={{ opacity: 0, x: -20, height: 0 }} animate={{ opacity: 1, x: 0, height: "auto" }}
                className={`flex items-center justify-between px-3 sm:px-5 py-2.5 border-b border-border/50 ${isYou ? "bg-primary/5" : isTop ? "bg-success/5" : ""}`}>
                <div className="flex items-center gap-2 min-w-0">
                  <div className={`h-1.5 w-1.5 rounded-full shrink-0 ${isYou ? "bg-primary" : isTop ? "bg-success" : "bg-muted-foreground/30"}`} />
                  <div className="min-w-0">
                    <p className={`text-sm font-sans truncate ${isYou ? "font-bold text-primary" : "font-medium text-foreground"}`}>
                      {getBidderName(bid)}
                    </p>
                    <p className="text-[10px] font-sans text-muted-foreground">
                      +{bid.increment} · {new Date(bid.created_at).toLocaleTimeString("en-IN", { hour: "2-digit", minute: "2-digit", second: "2-digit" })}
                    </p>
                  </div>
                </div>
                <p className={`text-sm font-sans font-semibold shrink-0 ${isYou ? "text-primary" : isTop ? "text-success" : "text-foreground"}`}>
                  ₹{Number(bid.bid_amount).toLocaleString("en-IN")}
                </p>
              </motion.div>
            );
          })}
        </AnimatePresence>
        {bidHistory.length === 0 && (
          <p className="text-xs font-sans text-muted-foreground text-center py-6">No bids yet</p>
        )}
      </CardContent>
    </Card>
  );
};

const formatGradeCell = (value: number | string | null | undefined) => {
  if (value === null || value === undefined || value === "") return "—";
  const n = Number(value);
  if (!Number.isFinite(n)) return "—";
  return `${n}%`;
};

const BatchDetails = ({ batch, details, showDetails, setShowDetails, sellerName, winnerName }: any) => {
  const sortedGrades = sortSizeGradesDesc(details.grades || []);
  const totals = sumGradingTotals(sortedGrades as any);

  return (
    <Card>
      <CardContent className="space-y-2.5 p-3">
        {/* Owner & Winner info — compact */}
        {(sellerName || (batch.status === "sold" && winnerName)) && (
          <div className="space-y-1">
            {sellerName && (
              <div className="flex items-center gap-1.5 rounded-md bg-secondary/50 px-2 py-1">
                <User className="h-3 w-3 text-primary shrink-0" />
                <span className="text-[10px] font-sans text-muted-foreground">Owner:</span>
                <span className="text-[11px] font-sans font-semibold text-foreground truncate">{sellerName}</span>
              </div>
            )}
            {batch.status === "sold" && winnerName && (
              <div className="flex items-center gap-1.5 rounded-md bg-success/10 px-2 py-1">
                <Crown className="h-3 w-3 text-success shrink-0" />
                <span className="text-[10px] font-sans text-muted-foreground">Won by:</span>
                <span className="text-[11px] font-sans font-semibold text-success truncate">{winnerName}</span>
                {batch.transferred_at && (
                  <Badge className="ml-auto bg-success/10 text-success border-0 text-[9px]">Transferred</Badge>
                )}
              </div>
            )}
          </div>
        )}

        {/* Size Grades & Quality table */}
         {sortedGrades.length > 0 ? (
          <div className="rounded-md border border-border/60 overflow-hidden">
            <table className="w-full table-fixed text-sm font-sans">
              <colgroup>
                <col className="w-[32%]" />
                <col className="w-[17%]" />
                <col className="w-[17%]" />
                <col className="w-[17%]" />
                <col className="w-[17%]" />
              </colgroup>
              <thead className="bg-secondary/60">
                <tr>
                  <th className="px-2 py-1 text-left font-semibold text-muted-foreground">Size</th>
                  <th className="px-1 py-1 text-right font-semibold text-muted-foreground">Clean</th>
                  <th className="px-1 py-1 text-right font-semibold text-muted-foreground">Mouth</th>
                  <th className="px-1 py-1 text-right font-semibold text-muted-foreground">Fruit</th>
                  <th className="px-1 py-1 text-right font-semibold text-muted-foreground">Sick</th>
                </tr>
              </thead>
              <tbody>
                {sortedGrades.map((g: any, idx: number) => (
                  <tr key={`${g.size_grade}-${idx}`} className={idx % 2 === 0 ? "bg-background" : "bg-secondary/30"}>
                    <td className="px-2 py-1 font-semibold text-foreground whitespace-nowrap">
                      {g.size_grade}
                      {g.size_percent != null && Number(g.size_percent) > 0 && (
                        <span className="ml-1 text-xs font-normal text-muted-foreground">{Number(g.size_percent)}%</span>
                      )}
                    </td>
                    <td className="px-1 py-1 text-right text-foreground tabular-nums">{formatGradeCell(g.clean_percent)}</td>
                    <td className="px-1 py-1 text-right text-foreground tabular-nums">{formatGradeCell(g.mouth_open_percent)}</td>
                    <td className="px-1 py-1 text-right text-foreground tabular-nums">{formatGradeCell(g.fruit_type_percent)}</td>
                    <td className="px-1 py-1 text-right text-foreground tabular-nums">{formatGradeCell(g.sick_percent)}</td>
                  </tr>
                ))}
              </tbody>
              <tfoot className="bg-secondary/40">
                <tr className="text-xs">
                  <td className="px-2 py-1 font-semibold text-muted-foreground">Total</td>
                  <td className="px-1 py-1 text-right font-semibold text-muted-foreground tabular-nums">{totals.clean}%</td>
                  <td className="px-1 py-1 text-right font-semibold text-muted-foreground tabular-nums">{totals.mouth}%</td>
                  <td className="px-1 py-1 text-right font-semibold text-muted-foreground tabular-nums">{totals.fruit}%</td>
                  <td className="px-1 py-1 text-right font-semibold text-muted-foreground tabular-nums">{totals.sick}%</td>
                </tr>
              </tfoot>
            </table>
          </div>
        ) : (
          <p className="text-xs font-sans text-muted-foreground">No size grades available</p>
        )}

        <BatchMediaGallery media={details.media} label="Lot Media" emptyMessage="No media available" />
      </CardContent>
    </Card>
  );
};

// ─── Admin Controls ───

const AdminControls = ({
  batch, isPaused, togglePause, updateBatchStatus, reducePrice, setReducePrice, handleReducePrice,
  queuedBatches, hasLiveBatch, tradeSummary, bidCount,
}: any) => (
  <div className="space-y-3">
    {/* Trade Summary */}
    {tradeSummary && (
      <Card>
        <CardContent className="p-3">
          <div className="flex items-center gap-2 mb-2">
            <BarChart3 className="h-3.5 w-3.5 text-primary" />
            <span className="text-xs font-sans font-semibold text-foreground">Trade Summary</span>
          </div>
          <div className="grid grid-cols-4 gap-2 text-center">
            <div className="rounded-lg bg-secondary/50 p-2">
              <p className="text-[9px] font-sans text-muted-foreground">Sold</p>
              <p className="text-sm font-sans font-bold text-success">{tradeSummary.sold}</p>
            </div>
            <div className="rounded-lg bg-secondary/50 p-2">
              <p className="text-[9px] font-sans text-muted-foreground">Queue</p>
              <p className="text-sm font-sans font-bold text-foreground">{tradeSummary.queued}</p>
            </div>
            <div className="rounded-lg bg-secondary/50 p-2">
              <p className="text-[9px] font-sans text-muted-foreground">Avg ₹/kg</p>
              <p className="text-sm font-sans font-bold text-primary">₹{tradeSummary.avgPrice > 0 ? tradeSummary.avgPrice.toFixed(0) : "—"}</p>
            </div>
            <div className="rounded-lg bg-secondary/50 p-2">
              <p className="text-[9px] font-sans text-muted-foreground">Total Value</p>
              <p className="text-sm font-sans font-bold text-accent-foreground">₹{tradeSummary.totalValue > 0 ? (tradeSummary.totalValue / 1000).toFixed(1) + "K" : "—"}</p>
            </div>
          </div>
        </CardContent>
      </Card>
    )}

    {/* Admin Action Buttons */}
    {batch && (
      <Card className="border-primary/30">
        <CardHeader className="pb-2 px-3 pt-3">
          <CardTitle className="font-display text-sm flex items-center gap-2">
            <Shield className="h-4 w-4 text-primary" /> Trade Controls
          </CardTitle>
        </CardHeader>
        <CardContent className="px-3 pb-3">
          <div className="grid grid-cols-2 gap-2">
            <Button size="sm" variant="outline" className="text-xs gap-1" onClick={() => togglePause(batch.id, isPaused)}>
              {isPaused ? <><Play className="h-3 w-3" /> Resume</> : <><Pause className="h-3 w-3" /> Pause</>}
            </Button>
            <Button size="sm" variant="outline" className="text-xs gap-1" onClick={() => updateBatchStatus(batch.id, "sold")}>
              <CheckCircle className="h-3 w-3" /> Close (Sold)
            </Button>
            <Dialog>
              <DialogTrigger asChild>
                <Button size="sm" variant="outline" className="text-xs gap-1" onClick={() => setReducePrice({ id: batch.id, price: String(batch.base_price) })}>
                  <TrendingDown className="h-3 w-3" /> Reduce Price
                </Button>
              </DialogTrigger>
              <DialogContent>
                <DialogHeader><DialogTitle className="font-display">Reduce Base Price</DialogTitle></DialogHeader>
                <div className="space-y-3 pt-2">
                  <p className="text-xs font-sans text-muted-foreground">Current base: ₹{Number(batch.base_price).toLocaleString("en-IN")}/kg</p>
                  {batch.current_highest_bid > 0 && (
                    <p className="text-xs font-sans text-success">Highest bid: ₹{Number(batch.current_highest_bid).toLocaleString("en-IN")} (stays valid)</p>
                  )}
                  <Input type="number" placeholder="New base price" value={reducePrice?.price || ""} onChange={(e) => setReducePrice({ id: batch.id, price: e.target.value })} />
                  <Button onClick={handleReducePrice} className="w-full" style={{ background: "var(--gradient-primary)" }}>Update Price</Button>
                </div>
              </DialogContent>
            </Dialog>
            <Button size="sm" variant="outline" className="text-xs gap-1 text-destructive border-destructive/30" onClick={() => updateBatchStatus(batch.id, "withdrawn")}>
              <XCircle className="h-3 w-3" /> Withdraw
            </Button>
          </div>
        </CardContent>
      </Card>
    )}

    {/* Queue */}
    {queuedBatches.length > 0 && (
      <Card>
        <CardHeader className="pb-2 px-3 pt-3">
          <CardTitle className="font-display text-sm flex items-center justify-between">
            <span className="flex items-center gap-2"><Package className="h-4 w-4 text-primary" /> Queue ({queuedBatches.length})</span>
            {!hasLiveBatch && queuedBatches[0] && <Badge className="bg-accent/10 text-accent-foreground text-[9px]">Next: {formatLotLabel(queuedBatches[0])}</Badge>}
          </CardTitle>
        </CardHeader>
        <CardContent className="px-3 pb-3 space-y-2">
          {queuedBatches.map((b: any) => (
            <div key={b.id} className="rounded-lg border border-border p-3 flex items-center justify-between">
              <div>
                <p className="text-sm font-sans font-semibold text-foreground">{formatLotLabel(b)}</p>
                <p className="text-[10px] font-sans text-muted-foreground">{b.quantity_kg} kg · Base: ₹{Number(b.base_price).toLocaleString("en-IN")}</p>
              </div>
              <Button size="sm" className="text-xs gap-1" disabled={hasLiveBatch} onClick={() => updateBatchStatus(b.id, "live")}>
                <Play className="h-3 w-3" /> Go Live
              </Button>
            </div>
          ))}
          {hasLiveBatch && <p className="text-[10px] font-sans text-muted-foreground text-center">Close current lot before starting next</p>}
        </CardContent>
      </Card>
    )}
  </div>
);

// ─── Trader Bid Buttons (with merged status chip + keyboard shortcuts) ───

const BidButtons = ({
  placing, activeBid, placeBid, currentBid, isPaused, isCooling, coolingSeconds, bidIncrements,
  hasBids, isLeading, isTied, batch,
}: any) => {
  const increments: number[] = bidIncrements && bidIncrements.length > 0 ? bidIncrements : [2, 4, 6, 8, 10];

  // Positional keyboard shortcuts: keys 1..9 map to increments[0..8]
  useEffect(() => {
    if (isPaused || placing || (isLeading && !isTied)) return;
    const handler = (e: KeyboardEvent) => {
      const target = e.target as HTMLElement | null;
      if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable)) return;
      if (e.metaKey || e.ctrlKey || e.altKey) return;
      const idx = parseInt(e.key, 10);
      if (Number.isNaN(idx) || idx < 1 || idx > increments.length) return;
      e.preventDefault();
      placeBid(increments[idx - 1]);
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [increments, placeBid, isPaused, placing, isLeading, isTied]);

  // Status chip (merged from former "You're leading / Outbid" card)
  let statusChip: React.ReactNode = null;
  if (isTied) {
    statusChip = (
      <Badge className="bg-warning text-warning-foreground border-0 text-[10px] gap-1">
        <AlertTriangle className="h-2.5 w-2.5" /> Tied
      </Badge>
    );
  } else if (hasBids) {
    statusChip = isLeading ? (
      <Badge className="bg-success text-success-foreground border-0 text-[10px] gap-1">
        <ChevronUp className="h-2.5 w-2.5" /> Leading · ₹{currentBid.toLocaleString("en-IN")}
      </Badge>
    ) : (
      <Badge className="bg-warning text-warning-foreground border-0 text-[10px] gap-1">
        <ChevronDown className="h-2.5 w-2.5" /> Outbid · ₹{currentBid.toLocaleString("en-IN")}
      </Badge>
    );
  }

  return (
  <Card>
    <CardHeader className="pb-2 px-3 sm:px-5 pt-3 sm:pt-4">
      <div className="flex items-center justify-between gap-2 flex-wrap">
        <CardTitle className="font-display text-sm sm:text-base flex items-center gap-2">
          <Gavel className="h-4 w-4 text-primary" /> {resolveLotType(batch)}
        </CardTitle>
        {statusChip}
      </div>
    </CardHeader>
    <CardContent className="px-3 sm:px-5 pb-3 sm:pb-4">
      {isCooling ? (
        <div className="text-center py-3 mb-2 rounded-lg bg-warning/10 text-warning text-xs font-sans font-semibold">
          Cooling… next lot starts in {coolingSeconds}s
        </div>
      ) : isPaused ? (
        <div className="text-center py-3 mb-2 rounded-lg bg-warning/10 text-warning text-xs font-sans font-semibold">
          Trade paused by admin
        </div>
      ) : isLeading && !isTied ? (
        <div className="text-center py-3 mb-2 rounded-lg bg-success/10 text-success text-xs font-sans font-semibold">
          You are leading · wait for someone to outbid you
        </div>
      ) : null}
      <div className={`grid gap-2`} style={{ gridTemplateColumns: `repeat(${Math.min(increments.length, 5)}, minmax(0, 1fr))` }}>
        {increments.map((inc: number, idx: number) => (
          <motion.div key={inc} whileTap={{ scale: 0.95 }}>
            <Button disabled={placing || isPaused || (isLeading && !isTied)}
              className={`relative w-full h-14 sm:h-16 text-xl sm:text-2xl font-sans font-bold rounded-xl shadow-sm bg-primary text-primary-foreground hover:bg-primary/90 ${activeBid === `+${inc}` ? "ring-2 ring-ring ring-offset-2" : ""}`}
              onClick={() => placeBid(inc)}
              title={`Press ${idx + 1} to bid +${inc}`}>
              <span>+{inc}</span>
              {idx < 9 && (
                <span className="absolute top-1 right-1.5 text-[9px] font-normal opacity-60 leading-none">
                  {idx + 1}
                </span>
              )}
            </Button>
          </motion.div>
        ))}
      </div>
      <p className="text-[10px] font-sans text-muted-foreground text-center mt-2 hidden sm:block">
        Tip: press keys <span className="font-mono font-semibold">1–{Math.min(increments.length, 9)}</span> on your keyboard to bid quickly
      </p>
    </CardContent>
  </Card>
  );
};

// ─── Unified Lot List (non-admin) ───

const UnifiedBatchList = ({ liveBatch, queuedBatches, batchDetails }: { liveBatch: any; queuedBatches: any[]; batchDetails: BatchDetailsState }) => {
  const [selectedBatch, setSelectedBatch] = useState<any>(null);
  const [sheetDetails, setSheetDetails] = useState<any>(null);
  const [loadingDetails, setLoadingDetails] = useState(false);

  // Combine live + queued into one list; live lot excluded if done
  const allItems = [
    ...(liveBatch ? [{ ...liveBatch, _isLive: true }] : []),
    ...queuedBatches.map((b) => ({ ...b, _isLive: false })),
  ];

  const openDetails = async (b: any) => {
    setSelectedBatch(b);
    if (b._isLive && batchDetails) {
      setSheetDetails({
        quality: batchDetails.quality,
        gl: batchDetails.gl,
        moisture: batchDetails.moisture,
        grades: batchDetails.grades,
        media: batchDetails.media || [],
      });
      setLoadingDetails(false);
      return;
    }
    setLoadingDetails(true);
    const lotKey = b.lot_id || b.id;
    const [distRes, lotRes, lotSizeRes, mediaMap] = await Promise.all([
      supabase.from("lot_size_distribution").select("*").eq("lot_id", b.id),
      supabase.from("lots").select("gl, moisture_percent, clean_percent, mouth_open_percent, fruit_type_percent, sick_percent, batch_color, is_artificial_coloured, is_single_graded, single_grade_size, custom_name, is_seeds, husk_percent, cardamom_percent, number_of_bags").eq("id", lotKey).maybeSingle(),
      ((supabase.from("lot_size_distribution" as any).select("*").eq("lot_id", lotKey) as any)),
      fetchLotMediaMap([lotKey]),
    ]);
    const batchGrades = distRes.data || [];
    const lotGrades = (lotSizeRes.data as any[]) || [];
    const lot: any = lotRes.data;
    const qs = batchGrades[0] || lot || {};
    const media = mediaMap[lotKey] || [];
    const sourceGrades = batchGrades.length > 0 ? batchGrades : lotGrades;
    const mergedGrades = lot?.is_seeds ? [] : buildPerSizeGradingRows(lot || {}, sourceGrades as any);
    setSelectedBatch((prev: any) => prev ? {
      ...prev,
      batch_color: lot?.batch_color ?? prev.batch_color ?? null,
      is_artificial_coloured: lot?.is_artificial_coloured ?? prev.is_artificial_coloured ?? false,
      is_single_graded: lot?.is_single_graded ?? prev.is_single_graded ?? false,
      single_grade_size: lot?.single_grade_size ?? prev.single_grade_size ?? null,
      custom_name: lot?.custom_name ?? prev.custom_name ?? null,
      is_seeds: lot?.is_seeds ?? prev.is_seeds ?? false,
      husk_percent: lot?.husk_percent ?? prev.husk_percent ?? null,
      cardamom_percent: lot?.cardamom_percent ?? prev.cardamom_percent ?? null,
    } : prev);
    setSheetDetails({
      quality: [
        { label: "Clean", value: formatPercentage(qs.clean_percent) },
        { label: "Mouth Open", value: formatPercentage(qs.mouth_open_percent) },
        { label: "Fruit Type", value: formatPercentage(qs.fruit_type_percent) },
        { label: "Sick", value: formatPercentage(qs.sick_percent) },
      ],
      gl: formatNumericValue(lot?.gl),
      moisture: formatPercentage(lot?.moisture_percent),
      grades: mergedGrades,
      media,
    });
    setLoadingDetails(false);
  };

  if (allItems.length === 0) return null;

  return (
    <>
      <div>
        <div className="flex items-center gap-2 mb-2">
          <Package className="h-4 w-4 text-primary" />
          <span className="font-display text-sm font-semibold text-foreground">Lots</span>
          <Badge variant="outline" className="text-[10px]">{allItems.length} lot{allItems.length !== 1 ? "es" : ""}</Badge>
        </div>
        <div className="space-y-2">
          {allItems.map((b: any, i: number) => {
            const queuePos = b._isLive ? null : i - (liveBatch ? 1 : 0) + 1;
            const tint = b._isLive ? undefined : resolveBatchLightTint(b);
            return (
              <motion.div key={b.id} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: i * 0.05 }}>
                <Card
                  className={`cursor-pointer hover:shadow-md transition-shadow ${b._isLive ? "border-live/50 bg-live/5" : "border-border/60"}`}
                  style={tint ? { backgroundColor: tint } : undefined}
                  onClick={() => openDetails(b)}
                >
                  <CardContent className="p-3 flex items-center justify-between">
                    <div className="flex items-center gap-3 min-w-0">
                      <div className={`h-8 w-8 rounded-lg flex items-center justify-center shrink-0 ${b._isLive ? "bg-live/20" : "bg-primary/10"}`}>
                        {b._isLive ? <Zap className="h-4 w-4 text-live" /> : <span className="text-xs font-bold text-primary">#{queuePos}</span>}
                      </div>
                      <div className="min-w-0">
                        <p className="text-sm font-sans font-semibold text-foreground truncate">{formatLotLabel(b)}</p>
                        <p className="text-sm font-sans text-muted-foreground">
                          <span className="font-semibold text-foreground">{b.quantity_kg} kg</span> · {b._isLive ? <span className="font-semibold text-foreground">Bid ₹{Number(b.current_highest_bid || b.base_price).toLocaleString("en-IN")}</span> : <span className="font-semibold text-foreground">Base ₹{Number(b.base_price).toLocaleString("en-IN")}</span>}
                        </p>
                      </div>
                    </div>
                    {b._isLive ? (
                      <Badge className="bg-live text-live-foreground border-0 text-[10px] gap-1 animate-pulse-live shrink-0"><Zap className="h-2.5 w-2.5" /> LIVE</Badge>
                    ) : (
                      <Badge variant="outline" className="text-[10px] capitalize border-0 bg-secondary text-secondary-foreground shrink-0">Queued</Badge>
                    )}
                  </CardContent>
                </Card>
              </motion.div>
            );
          })}
        </div>
      </div>

      {/* ── Bottom Sheet ── */}
      <Sheet open={!!selectedBatch} onOpenChange={(open) => { if (!open) { setSelectedBatch(null); setSheetDetails(null); } }}>
        <SheetContent side="bottom" className="rounded-t-2xl max-h-[80vh] overflow-y-auto px-4 pb-6 pt-3">
          {/* Handle */}
          <div className="flex justify-center mb-3">
            <div className="w-10 h-1 rounded-full bg-border" />
          </div>

          {selectedBatch && (
            <div className="space-y-2.5">
              {/* Title row */}
              <div className="flex items-center justify-between gap-2">
                <div className="min-w-0">
                  <div className="flex items-center gap-2">
                    <h3 className="font-display text-xl font-bold text-foreground truncate">
                      {selectedBatch.lot_seq != null ? `Lot #${selectedBatch.lot_seq}` : selectedBatch.batch_number}
                    </h3>
                    {selectedBatch._isLive && (
                      <Badge className="bg-live text-live-foreground border-0 text-xs gap-1 animate-pulse-live"><Zap className="h-3 w-3" /> LIVE</Badge>
                    )}
                  </div>
                  <p className="text-sm font-sans text-muted-foreground mt-0.5">
                    {getLotTypeLabel(selectedBatch)}
                    {selectedBatch.is_artificial_coloured && !selectedBatch.is_seeds ? " · Artificial Coloured" : ""}
                  </p>
                </div>
                {!selectedBatch._isLive && (
                  <Badge variant="outline" className="text-xs capitalize border-0 bg-secondary text-secondary-foreground shrink-0">queued</Badge>
                )}
              </div>

              {/* Top metrics row: Qty / Bags / Base / [Current Bid] / g/L / Moisture */}
              <div className={`grid gap-1.5 ${selectedBatch._isLive ? (selectedBatch.is_seeds ? "grid-cols-4 sm:grid-cols-8" : "grid-cols-3 sm:grid-cols-6") : (selectedBatch.is_seeds ? "grid-cols-4 sm:grid-cols-7" : "grid-cols-5")}`}>
                {[
                  { label: "Qty", value: `${selectedBatch.quantity_kg} kg` },
                  { label: "Bags", value: selectedBatch.number_of_bags != null ? Number(selectedBatch.number_of_bags).toLocaleString("en-IN") : "—" },
                  { label: "Base", value: `₹${Number(selectedBatch.base_price).toLocaleString("en-IN")}` },
                  ...(selectedBatch._isLive ? [{
                    label: "Current",
                    value: `₹${Number(selectedBatch.current_highest_bid || selectedBatch.base_price).toLocaleString("en-IN")}`,
                    highlight: true,
                  }] : []),
                  { label: "LTR/WT", value: sheetDetails?.gl ?? "—" },
                  { label: "Moisture", value: sheetDetails?.moisture ?? "—" },
                  ...(selectedBatch.is_seeds ? [
                    { label: "Husk", value: (selectedBatch as any).husk_percent != null ? `${Number((selectedBatch as any).husk_percent)}%` : "—" },
                    { label: "Cardamom", value: (selectedBatch as any).cardamom_percent != null ? `${Number((selectedBatch as any).cardamom_percent)}%` : "—" },
                  ] : []),
                ].map((m: any) => (
                  <div
                    key={m.label}
                    className={`rounded-lg border px-2 py-2 ${m.highlight ? "border-primary/40 bg-primary/5" : "border-border/60 bg-secondary/20"}`}
                  >
                    <p className="text-[11px] font-sans text-muted-foreground uppercase tracking-wide">{m.label}</p>
                    <p className={`text-sm font-sans font-bold mt-0.5 truncate ${m.highlight ? "text-primary" : "text-foreground"}`}>{m.value}</p>
                  </div>
                ))}
              </div>

              {loadingDetails ? (
                <div className="flex justify-center py-6"><div className="h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" /></div>
              ) : sheetDetails && (
                <>
                  {/* Size × Quality table */}
                  {sheetDetails.grades.length > 0 && (() => { const totals = sumGradingTotals(sheetDetails.grades as any); return (
                    <div>
                      <p className="text-sm font-sans font-semibold text-foreground mb-1.5">Size Grades & Quality</p>
                      <div className="overflow-hidden rounded-lg border border-border/60">
                        <table className="w-full table-fixed text-xs font-sans">
                          <colgroup>
                            <col className="w-[28%]" />
                            <col className="w-[18%]" />
                            <col className="w-[18%]" />
                            <col className="w-[18%]" />
                            <col className="w-[18%]" />
                          </colgroup>
                          <thead className="bg-secondary/60">
                            <tr className="text-left text-xs text-muted-foreground">
                              <th className="px-2 py-1.5 font-semibold">Size</th>
                              <th className="px-2 py-1.5 font-semibold text-right whitespace-nowrap">{labelWithPct("Clean", totals.clean)}</th>
                              <th className="px-2 py-1.5 font-semibold text-right whitespace-nowrap">{labelWithPct("Mouth", totals.mouth)}</th>
                              <th className="px-2 py-1.5 font-semibold text-right whitespace-nowrap">{labelWithPct("Fruit", totals.fruit)}</th>
                              <th className="px-2 py-1.5 font-semibold text-right whitespace-nowrap">{labelWithPct("Sick", totals.sick)}</th>
                            </tr>
                          </thead>
                          <tbody>
                            {sheetDetails.grades.map((g: any, idx: number) => (
                              <tr key={g.id} className={idx % 2 === 0 ? "bg-background text-foreground" : "bg-secondary/30 text-foreground"}>
                                <td className="px-2 py-1.5 font-semibold whitespace-nowrap">{g.size_percent != null && Number(g.size_percent) > 0 ? `${g.size_grade} (${Number(g.size_percent)}%)` : g.size_grade}</td>
                                <td className="px-2 py-1.5 text-right tabular-nums">{formatPercentage(g.clean_percent)}</td>
                                <td className="px-2 py-1.5 text-right tabular-nums">{formatPercentage(g.mouth_open_percent)}</td>
                                <td className="px-2 py-1.5 text-right tabular-nums">{formatPercentage(g.fruit_type_percent)}</td>
                                <td className="px-2 py-1.5 text-right tabular-nums">{formatPercentage(g.sick_percent)}</td>
                              </tr>
                            ))}
                          </tbody>
                        </table>
                      </div>
                    </div>
                  ); })()}

                  {/* Media */}
                  {sheetDetails.media && sheetDetails.media.length > 0 && (
                    <div>
                      <p className="text-sm font-sans font-semibold text-foreground mb-2">Photos & Videos</p>
                      <BatchMediaGallery media={sheetDetails.media} label="" />
                    </div>
                  )}
                </>
              )}
            </div>
          )}
        </SheetContent>
      </Sheet>
    </>
  );
};

// ─── Farmer Status Card ───

const FarmerStatusCard = ({ batch, currentBid }: any) => (
  <Card className="border-primary/20">
    <CardContent className="p-3">
      <div className="flex items-center gap-2 mb-2">
        <Eye className="h-4 w-4 text-primary" />
        <span className="text-xs font-sans font-semibold text-foreground">Watching as Farmer</span>
      </div>
      <div className="rounded-lg bg-primary/5 p-3 flex items-center justify-between">
        <span className="text-xs font-sans text-muted-foreground">Current Bid</span>
        <span className="font-sans text-sm font-bold text-primary">₹{currentBid.toLocaleString("en-IN")}/kg</span>
      </div>
      {batch.seller_id && (
        <p className="text-[10px] font-sans text-muted-foreground mt-2 text-center">
          You'll be notified when your lot is sold
        </p>
      )}
    </CardContent>
  </Card>
);

// ─── Tied Bids Winner Picker (Admin) ───

const TiedBidsPicker = ({ batch, tiedBidders, onSelectWinner }: any) => {
  if (!batch || !tiedBidders || tiedBidders.length <= 1) return null;
  const topBid = Number(batch.current_highest_bid || batch.base_price);

  return (
    <Card className="border-warning/50 bg-warning/5">
      <CardHeader className="pb-2 px-3 pt-3">
        <CardTitle className="font-display text-sm flex items-center gap-2 text-warning">
          <AlertTriangle className="h-4 w-4" /> Tied Bids – Select Winner
        </CardTitle>
      </CardHeader>
      <CardContent className="px-3 pb-3">
        <p className="text-xs font-sans text-muted-foreground mb-3">
          {tiedBidders.length} traders bid ₹{topBid.toLocaleString("en-IN")}/kg. Pick the winner:
        </p>
        <div className="space-y-2">
          {tiedBidders.map((bidder: any) => (
            <div key={bidder.user_id} className="rounded-lg border border-border p-3 flex items-center justify-between">
              <div>
                <p className="text-sm font-sans font-semibold text-foreground">{bidder.firm_name || bidder.full_name}</p>
                <p className="text-[10px] font-sans text-muted-foreground">Bid: ₹{topBid.toLocaleString("en-IN")}/kg</p>
              </div>
              <Button size="sm" className="text-xs gap-1" onClick={() => onSelectWinner(bidder.user_id)}
                style={{ background: "var(--gradient-primary)" }}>
                <Crown className="h-3 w-3" /> Award
              </Button>
            </div>
          ))}
        </div>
      </CardContent>
    </Card>
  );
};

// ─── Main Component ───

const LiveTrade = () => {
  const { user, roles, profile } = useAuth();
  const { toast } = useToast();
  const { settings: adminSettings } = useAdminSettings();
  const queryClient = useQueryClient();
  const [batch, setBatch] = useState<any>(null);
  const [allBatches, setAllBatches] = useState<any[]>([]);
  const [bidHistory, setBidHistory] = useState<any[]>([]);
  const [loading, setLoading] = useState(() => {
    const cached = queryClient.getQueryData(["live-trade-init"]);
    return !cached;
  });
  const [activeBid, setActiveBid] = useState<string | null>(null);
  const [placing, setPlacing] = useState(false);
  const [bidCooldown, setBidCooldown] = useState(false);
  // SINGLE timer source — admin and trader views consume the same hook.
  const timerState = useBatchTimer(batch, adminSettings.timer_duration_seconds || 15, adminSettings.cooling_delay_seconds || 0);
  const isCooling = timerState.isCooling;
  const coolingSeconds = timerState.seconds;
  const seconds = timerState.isPaused ? -1 : timerState.seconds;
  const [showDetails, setShowDetails] = useState(true);
  const [bidCount, setBidCount] = useState(0);
  const [batchDetails, setBatchDetails] = useState<BatchDetailsState>(emptyBatchDetails);
  const [reducePrice, setReducePrice] = useState<{ id: string; price: string } | null>(null);
  const [sellerName, setSellerName] = useState<string | null>(null);
  const [winnerName, setWinnerName] = useState<string | null>(null);
  const [liveSession, setLiveSession] = useState<any>(null);
  const [tiedBidders, setTiedBidders] = useState<any[]>([]);
  const [bidFlash, setBidFlash] = useState<number | null>(null);
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);

  const isAdmin = roles?.includes("admin");
  const isUnified = roles?.includes("unified");
  const isTrader = roles?.includes("trader") || isUnified;
  const isFarmerOnly = roles?.includes("farmer") && !isTrader && !isAdmin;
  const { isApproved } = useApprovalGate();

  const hasLiveBatch = !!batch;
  const activeTradeId = liveSession?.id ?? batch?.trade_id ?? null;
  const queuedBatches = useMemo(
    () =>
      allBatches
        .filter((b) => b.status === "queued" && (!activeTradeId || b.trade_id === activeTradeId))
        .sort((a, b) => {
          const sa = a.lot_seq ?? Number.MAX_SAFE_INTEGER;
          const sb = b.lot_seq ?? Number.MAX_SAFE_INTEGER;
          if (sa !== sb) return sa - sb;
          return new Date(a.created_at).getTime() - new Date(b.created_at).getTime();
        }),
    [allBatches, activeTradeId],
  );
  const soldBatches = useMemo(
    () => allBatches.filter((b) => b.status === "sold" && (!activeTradeId || b.trade_id === activeTradeId)),
    [allBatches, activeTradeId],
  );

  const tradeSummary = useMemo(() => {
    if (!activeTradeId) return null;
    const sessionBatches = allBatches.filter((b) => b.trade_id === activeTradeId);
    const sold = sessionBatches.filter((b) => b.status === "sold");
    const queued = sessionBatches.filter((b) => b.status === "queued");
    const totalValue = sold.reduce((s, b) => s + (Number(b.current_highest_bid || b.base_price) * Number(b.quantity_kg)), 0);
    const totalQty = sold.reduce((s, b) => s + Number(b.quantity_kg), 0);
    return { sold: sold.length, queued: queued.length, totalValue, avgPrice: totalQty > 0 ? totalValue / totalQty : 0 };
  }, [allBatches, activeTradeId]);

  // Fetch live lot + all relevant lots + session
  const fetchData = useCallback(async () => {
    const [batchRes, sessionRes] = await Promise.all([
      supabase.from("lots").select("*").eq("status", "live").order("created_at", { ascending: true }).limit(1).maybeSingle(),
      supabase.from("trade_sessions").select("*").eq("status", "live").limit(1),
    ]);

    const activeSession = sessionRes.data?.[0] || null;
    const activeTradeIdFromBatch = (batchRes.data as any)?.trade_id ?? null;
    const activeTradeId = activeSession?.id ?? activeTradeIdFromBatch;
    const { data: relevantBatches = [] } = activeTradeId
      ? await supabase.from("lots").select("*").eq("trade_id", activeTradeId).order("created_at", { ascending: true })
      : { data: [] as any[] };

    // Enrich batches with lot-level descriptors (colour, type, single grade) so
    // queue cards can render the correct light tint and labels.
    const lotIds = Array.from(new Set((relevantBatches || []).map((b: any) => b.lot_id).filter(Boolean)));
    const { data: lotsForList } = lotIds.length
      ? await supabase.from("lots").select("id, batch_color, is_artificial_coloured, is_single_graded, single_grade_size, custom_name, is_seeds").in("id", lotIds)
      : { data: [] as any[] };
    const lotMap = new Map<string, any>((lotsForList || []).map((l: any) => [l.id, l]));
    const enrichedBatches = (relevantBatches || []).map((b: any) => {
      const lot = b.lot_id ? lotMap.get(b.lot_id) : null;
      return {
        ...b,
        batch_color: lot?.batch_color ?? b.batch_color ?? null,
        is_artificial_coloured: lot?.is_artificial_coloured ?? b.is_artificial_coloured ?? false,
        is_single_graded: lot?.is_single_graded ?? b.is_single_graded ?? false,
        single_grade_size: lot?.single_grade_size ?? b.single_grade_size ?? null,
        custom_name: lot?.custom_name ?? b.custom_name ?? null,
        is_seeds: lot?.is_seeds ?? b.is_seeds ?? false,
      };
    });

    setAllBatches(enrichedBatches);
    setLiveSession(activeSession);

    const liveLot: any = batchRes.data;
    if (liveLot) {
      const [bidsRes, lotSizeRes, lotMediaMap, sellerRes, winnerRes] = await Promise.all([
        supabase.from("bids").select("*, profiles(full_name, firm_name)").eq("lot_id", liveLot.id).order("created_at", { ascending: false }).limit(20),
        ((supabase.from("lot_size_distribution" as any).select("*").eq("lot_id", liveLot.id) as any)),
        fetchLotMediaMap([liveLot.id]),
        liveLot.seller_id
          ? supabase.from("profiles").select("full_name, firm_name").eq("id", liveLot.seller_id).single()
          : Promise.resolve({ data: null }),
        liveLot.highest_bidder_id
          ? supabase.from("profiles").select("full_name, firm_name").eq("id", liveLot.highest_bidder_id).single()
          : Promise.resolve({ data: null }),
      ]);
      setBidHistory(bidsRes.data || []);
      setBidCount((bidsRes.data || []).length);
      setSellerName(sellerRes.data ? (sellerRes.data as any).firm_name || (sellerRes.data as any).full_name || null : null);
      setWinnerName(winnerRes.data ? (winnerRes.data as any).firm_name || (winnerRes.data as any).full_name || null : null);
      setBatch(liveLot);
      const lotGrades = (lotSizeRes.data as any[]) || [];
      const mergedGrades = buildPerSizeGradingRows(liveLot, lotGrades);
      setBatchDetails({
        quality: [
          { label: "Clean", value: formatPercentage(liveLot.clean_percent) },
          { label: "Mouth Open", value: formatPercentage(liveLot.mouth_open_percent) },
          { label: "Fruit Type", value: formatPercentage(liveLot.fruit_type_percent) },
          { label: "Sick", value: formatPercentage(liveLot.sick_percent) },
        ],
        grades: mergedGrades,
        media: lotMediaMap[liveLot.id] || [],
        gl: formatNumericValue(liveLot.gl),
        moisture: formatPercentage(liveLot.moisture_percent),
      });

      // Check for tied bids at the top price
      const topBid = Number(batchRes.data.current_highest_bid || 0);
      if (topBid > 0 && !batchRes.data.highest_bidder_id) {
        const { data: tiedBidsData } = await supabase
          .from("bids")
          .select("user_id, profiles(full_name, firm_name)")
          .eq("lot_id", batchRes.data.id)
          .eq("bid_amount", topBid);
        const seen = new Set();
        const unique = (tiedBidsData || []).filter((b: any) => {
          if (seen.has(b.user_id)) return false;
          seen.add(b.user_id);
          return true;
        }).map((b: any) => ({ user_id: b.user_id, full_name: b.profiles?.full_name, firm_name: b.profiles?.firm_name }));
        setTiedBidders(unique.length > 1 ? unique : []);
      } else {
        setTiedBidders([]);
      }
    } else {
      setBatch(null);
      setBidHistory([]);
      setBidCount(0);
      setBatchDetails(emptyBatchDetails);
      setTiedBidders([]);
      setSellerName(null);
      setWinnerName(null);
    }
    queryClient.setQueryData(["live-trade-init"], true);
    setLoading(false);
  }, [queryClient]);

  // Restore cached state on mount if available, then refresh in background
  useEffect(() => {
    const cached = queryClient.getQueryData(["live-trade-init"]);
    if (cached) {
      // Data from previous visit exists in local state via React's fast remount
      // Just fetch fresh data in background without showing skeleton
      fetchData();
    } else {
      fetchData();
    }
  }, [fetchData, queryClient]);

  // Mobile WebViews / backgrounded tabs freeze JS timers AND can drop the
  // Realtime WebSocket. When the user returns, our local `lot.timer_ends_at`
  // may be stale — the countdown then ticks against an old anchor and shows a
  // wrong value (e.g. "10s left" when the server already moved to a new lot).
  // Fix: on tab-resume, refetch the live lot row ONCE so the timer hook
  // re-anchors against the fresh server-side `timer_ends_at`.
  // Cost: at most one REST call per resume event. No new realtime channels,
  // no polling, no extra heartbeats.
  useEffect(() => {
    const onVisible = () => {
      if (typeof document !== "undefined" && document.visibilityState === "visible") {
        fetchData();
      }
    };
    document.addEventListener("visibilitychange", onVisible);
    window.addEventListener("pageshow", onVisible);
    return () => {
      document.removeEventListener("visibilitychange", onVisible);
      window.removeEventListener("pageshow", onVisible);
    };
  }, [fetchData]);

  // Whenever a new server-driven timer begins, refresh the shared clock offset
  // so countdowns stay aligned across viewers. The actual ticking happens in the
  // The shared server clock auto-resyncs every 60s. Re-measuring on every
  // timer_ends_at change introduces ~10–50ms offset jitter that visually
  // flicks the countdown by ±1s right after a pause/resume, so we don't
  // force a resync here anymore.

  // Keep-warm loop removed: it was generating background function traffic from every trader tab.

  // Single shared heartbeat — same cadence as /admin so every viewer triggers
  // the same idempotent server-side `check-timer` and no screen ticks alone.
  useTimerHeartbeat(!!batch && batch.status === "live", 4000);

  // Realtime: only the active trade/session changes
  useEffect(() => {
    if (!activeTradeId) return;

    const channel = supabase
      .channel(`live-trade-${activeTradeId}`)
      .on("postgres_changes", { event: "*", schema: "public", table: "lots", filter: `trade_id=eq.${activeTradeId}` }, (payload) => {
        if (payload.eventType === "DELETE") {
          const oldId = (payload.old as any)?.id;
          setAllBatches((prev) => prev.filter((b) => b.id !== oldId));
          setBatch((prev: any) => prev?.id === oldId ? null : prev);
          return;
        }
        const updated = payload.new as any;
        setAllBatches((prev) => {
          const idx = prev.findIndex((b) => b.id === updated.id);
          if (idx >= 0) {
            const copy = [...prev];
            copy[idx] = updated;
            return copy;
          }
          return [...prev, updated].sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
        });
        setBatch((prev: any) => {
          if (!prev && updated.status === "live") {
            setTimeout(() => fetchData(), 0);
            return prev;
          }
          if (prev && updated.id === prev.id) {
            if (updated.status !== "live") {
              setTimeout(() => fetchData(), 0);
              return null;
            }
            return { ...prev, ...updated };
          }
          return prev;
        });
      })
      .on("postgres_changes", { event: "*", schema: "public", table: "trade_sessions", filter: `id=eq.${activeTradeId}` }, (payload) => {
        if (payload.eventType === "DELETE") {
          setLiveSession(null);
          return;
        }
        const updated = payload.new as any;
        setLiveSession(updated);
        if (updated.status !== "live") {
          setTimeout(() => fetchData(), 0);
        }
      })
      .subscribe();
    return () => { supabase.removeChannel(channel); };
  }, [activeTradeId, fetchData]);

  // Profile cache for live bid feed — avoids repeated DB lookups for the same bidder
  const profileCacheRef = useRef<Map<string, { full_name: string | null; firm_name: string | null }>>(new Map());

  // Realtime: bids for current lot
  useEffect(() => {
    if (!batch?.id) return;
    const channel = supabase
      .channel(`live-trade-bids-${batch.id}`)
      .on("postgres_changes", { event: "INSERT", schema: "public", table: "bids", filter: `lot_id=eq.${batch.id}` }, async (payload) => {
        const newBid = payload.new as any;
        // Use cached profile when available — sub-millisecond UI update
        let profile = profileCacheRef.current.get(newBid.user_id);
        if (!profile) {
          const { data } = await supabase.from("profiles").select("full_name, firm_name").eq("id", newBid.user_id).maybeSingle();
          profile = data as any || { full_name: null, firm_name: null };
          profileCacheRef.current.set(newBid.user_id, profile);
        }
        setBidHistory((prev) => [{ ...newBid, profiles: profile }, ...prev.slice(0, 19)]);
        setBidCount((c) => c + 1);
        // Outbid/Leading badges are derived from state (bidHistory + highest_bidder_id),
        // so they persist as long as the condition holds.
        // #4 Bid flash
        const newAmount = Number(newBid.bid_amount);
        setBatch((prev: any) => {
          if (!prev) return prev;
          const currentHighest = Number(prev.current_highest_bid || 0);
          if (newAmount > currentHighest) {
            const diff = newAmount - currentHighest;
            setBidFlash(diff);
            setTimeout(() => setBidFlash(null), 900);
            return { ...prev, current_highest_bid: newAmount };
          }
          return prev;
        });
      })
      .subscribe();
    return () => { supabase.removeChannel(channel); };
  }, [batch?.id]);

  // Auto-queue next lot after sold (admin manual-close fallback only).
  // Timer-expiry auto-close is handled server-side by check-timer to avoid races.
  // We immediately enter a COOLING state on the next lot (live + paused with
  // timer_ends_at = now + coolingDelay). The server-side check-timer then
  // promotes it to a real auction once cooling elapses — so the cooldown is
  // visible to every participant and survives admin tab close / navigation.
  const autoQueueNext = useCallback(async (tradeId: string) => {
    if (!isAdmin) return;
    if (!adminSettings.auto_live_enabled) return;
    const cool = Math.max(0, adminSettings.cooling_delay_seconds || 0);
    const { data: nextQueued } = await supabase
      .from("lots")
      .select("id")
      .eq("trade_id", tradeId)
      .eq("status", "queued")
      .order("created_at", { ascending: true })
      .limit(1);
    if (!nextQueued || nextQueued.length === 0) return;
    const nextId = nextQueued[0].id;
    await startBatchCooling({
      batchId: nextId,
      coolingSeconds: cool,
      timerDurationSeconds: adminSettings.timer_duration_seconds || 15,
    });
    toast({ title: cool > 0 ? `Cooling ${cool}s before next lot…` : "Next lot auto-started" });
  }, [toast, adminSettings, isAdmin]);

  // ─── Admin Actions ───
  const updateBatchStatus = async (id: string, status: string) => {
    if (status === "live") {
      if (hasLiveBatch) {
        toast({ title: "Cannot go live", description: "Close the current live lot first", variant: "destructive" });
        return;
      }
      await supabase.from("lots").update({ status: "live" as any }).eq("id", id);
      await supabase.rpc("timer_start_live" as never, { p_lot_id: id, p_duration_seconds: adminSettings.timer_duration_seconds || 15 } as never);
    } else if (status === "sold") {
      const batchToClose = allBatches.find((b: any) => b.id === id);
      const resolution = await resolveTopBidResolution(
        id,
        Number(batchToClose?.current_highest_bid || 0),
        batchToClose?.highest_bidder_id,
      );

      if (resolution.state === "tie") {
        await supabase.rpc("timer_mark_tie_paused" as never, { p_lot_id: id } as never);
        toast({
          title: "Timer paused due to tied highest bid",
          description: `${resolution.uniqueBidders.length} traders tied at ₹${resolution.topBid.toLocaleString("en-IN")}. Select winner to complete sale.`,
          variant: "destructive",
        });
        return;
      }

      const winnerId = resolution.state === "winner" ? resolution.winnerId : batchToClose?.highest_bidder_id ?? null;
      await supabase.from("lots").update({
        status: "sold" as any,
        highest_bidder_id: winnerId,
      }).eq("id", id);
      await supabase.rpc("timer_clear" as never, { p_lot_id: id } as never);

      // Notify winner (green)
      if (winnerId) {
        await supabase.from("notifications").insert({
          user_id: winnerId,
          title: "You won the trade!",
          message: `Lot ${batchToClose?.lot_number} — ₹${resolution.topBid.toLocaleString("en-IN")}/kg × ${batchToClose?.quantity_kg}kg`,
          type: "won",
        });
      }

      // Notify all losing bidders (red)
      const { data: allBidders } = await supabase.from("bids").select("user_id").eq("lot_id", id);
      const allUnique = [...new Set((allBidders || []).map((b: any) => b.user_id))];
      const losers = allUnique.filter((uid: string) => uid !== winnerId);
      if (losers.length > 0) {
        await supabase.from("notifications").insert(
          losers.map((uid: string) => ({
            user_id: uid,
            title: "You lost — Lot sold",
            message: `Lot ${batchToClose?.lot_number} was sold at ₹${resolution.topBid.toLocaleString("en-IN")}/kg`,
            type: "lost",
          }))
        );
      }

      // Notify seller (green)
      if (batchToClose?.seller_id) {
        await supabase.from("notifications").insert({
          user_id: batchToClose.seller_id,
          title: "Your lot was sold!",
          message: `Lot ${batchToClose.lot_number} sold at ₹${resolution.topBid.toLocaleString("en-IN")}/kg`,
          type: "won",
        });
      }

      toast({ title: `Lot sold` });
      if (batchToClose?.trade_id) autoQueueNext(batchToClose.trade_id);
      return;
    } else if (status === "withdrawn") {
      const batchToWithdraw = allBatches.find((b: any) => b.id === id);
      await supabase.from("lots").update({ status: "withdrawn" as any }).eq("id", id);
      await supabase.rpc("timer_clear" as never, { p_lot_id: id } as never);
      if (batchToWithdraw?.lot_id) {
        const { data: lot } = await supabase.from("lots").select("status").eq("id", batchToWithdraw.lot_id).maybeSingle();
        if (lot?.status === "scheduled") {
          await supabase.from("lots").update({ status: "graded" }).eq("id", batchToWithdraw.lot_id);
        }
      }

      // Notify all bidders + seller about withdrawal (red)
      const { data: allBidders } = await supabase.from("bids").select("user_id").eq("lot_id", id);
      const allUnique = [...new Set((allBidders || []).map((b: any) => b.user_id))];
      const notifyIds = batchToWithdraw?.seller_id ? [...new Set([...allUnique, batchToWithdraw.seller_id])] : allUnique;
      if (notifyIds.length > 0) {
        await supabase.from("notifications").insert(
          notifyIds.map((uid: string) => ({
            user_id: uid,
            title: "Lot withdrawn",
            message: `Lot ${batchToWithdraw?.lot_number} has been withdrawn from trade`,
            type: "lost",
          }))
        );
      }
      toast({ title: `Lot withdrawn` });
      if (batchToWithdraw?.trade_id) autoQueueNext(batchToWithdraw.trade_id);
      return;
    } else {
      await supabase.from("lots").update({ status: status as any }).eq("id", id);
      await supabase.rpc("timer_clear" as never, { p_lot_id: id } as never);
    }
    toast({ title: `Lot ${status}` });
  };

  const togglePause = async (id: string, currentlyPaused: boolean) => {
    const defaultDuration = adminSettings.timer_duration_seconds || 15;
    try {
      await toggleBatchPause({ batchId: id, currentlyPaused, durationSeconds: defaultDuration });
      toast({ title: currentlyPaused ? "Trade resumed" : "Trade paused" });
    } catch (e: any) {
      toast({ title: "Action blocked", description: e?.message || "Cannot pause/resume this lot right now.", variant: "destructive" });
    }
  };

  const handleReducePrice = async () => {
    if (!reducePrice || !reducePrice.price || !batch) return;
    const newPrice = Number(reducePrice.price);
    await supabase.from("lots").update({ base_price: newPrice } as any).eq("id", reducePrice.id);
    await supabase.from("price_history").insert({
      lot_id: reducePrice.id,
      old_price: batch.base_price,
      new_price: newPrice,
    });
    toast({ title: "Base price reduced" });
    setReducePrice(null);
  };

  // ─── Trader Bid (tied-bid model) ───
  const placeBid = useCallback(async (increment: number) => {
    if (!batch || placing || bidCooldown) return;
    setPlacing(true);
    setBidCooldown(true);
    setActiveBid(`+${increment}`);

    const currentPriceSeen = Number(batch.current_highest_bid || 0) > 0
      ? Number(batch.current_highest_bid)
      : Number(batch.base_price);

    // Optimistic UI: bump local price immediately for instant feedback
    const optimisticPrice = currentPriceSeen + increment;
    setBatch((prev: any) => prev && prev.id === batch.id
      ? { ...prev, current_highest_bid: optimisticPrice }
      : prev);

    // Fire-and-forget invoke (no pre-flight session check — supabase-js auto-refreshes)
    supabase.functions
      .invoke("place-bid", {
        body: { lot_id: batch.id, increment, current_price_seen: currentPriceSeen },
      })
      .then(({ data, error }) => {
        if (error || data?.error) {
          const msg = data?.error || error?.message;
          toast({ title: "Bid failed", description: msg, variant: "destructive" });
        } else if (data?.is_tied) {
          toast({ title: `Bid placed: ₹${data.bid_amount.toLocaleString("en-IN")} (${data.tied_bidders} tied)` });
        }
      })
      .finally(() => setPlacing(false));

    // Quick reset of the visual flash so users can tap again fast
    setTimeout(() => setActiveBid(null), 150);
    // 1.5s rate-limit guard — matches server-side check
    setTimeout(() => setBidCooldown(false), 1500);
  }, [batch, placing, bidCooldown, toast]);

  // ─── Admin: Select winner from tied bids ───
  const selectWinner = useCallback(async (winnerId: string) => {
    if (!batch) return;
    const topBid = Number(batch.current_highest_bid);
    await supabase.from("lots").update({
      highest_bidder_id: winnerId,
      status: "sold" as any,
    }).eq("id", batch.id);
    await supabase.rpc("timer_clear" as never, { p_lot_id: batch.id } as never);

    // Notify winner (green — tied won)
    await supabase.from("notifications").insert({
      user_id: winnerId,
      title: "Tied bid — You won!",
      message: `Lot ${batch.lot_number} awarded to you at ₹${topBid.toLocaleString("en-IN")}/kg`,
      type: "won",
    });

    // Notify tied losers (red)
    const tiedLoserIds = tiedBidders.filter((b: any) => b.user_id !== winnerId).map((b: any) => b.user_id);
    if (tiedLoserIds.length > 0) {
      await supabase.from("notifications").insert(
        tiedLoserIds.map((uid: string) => ({
          user_id: uid,
          title: "Tied bid — You lost",
          message: `Lot ${batch.lot_number} was awarded to another bidder at ₹${topBid.toLocaleString("en-IN")}/kg`,
          type: "lost",
        }))
      );
    }

    // Notify all other losing bidders
    const { data: allBidders } = await supabase.from("bids").select("user_id").eq("lot_id", batch.id);
    const allUnique = [...new Set((allBidders || []).map((b: any) => b.user_id))];
    const otherLosers = allUnique.filter((uid: string) => uid !== winnerId && !tiedLoserIds.includes(uid));
    if (otherLosers.length > 0) {
      await supabase.from("notifications").insert(
        otherLosers.map((uid: string) => ({
          user_id: uid,
          title: "You lost — Lot sold",
          message: `Lot ${batch.lot_number} was sold at ₹${topBid.toLocaleString("en-IN")}/kg`,
          type: "lost",
        }))
      );
    }

    // Notify seller (green)
    if (batch.seller_id) {
      await supabase.from("notifications").insert({
        user_id: batch.seller_id,
        title: "Your lot was sold!",
        message: `Lot ${batch.lot_number} sold at ₹${topBid.toLocaleString("en-IN")}/kg`,
        type: "won",
      });
    }

    toast({ title: "Winner selected & lot sold" });
    setTiedBidders([]);
    autoQueueNext(batch.trade_id);
  }, [batch, toast, autoQueueNext, tiedBidders]);

  const currentBid = batch ? Number(batch.current_highest_bid || batch.base_price) : 0;
  const isPaused = batch?.is_paused === true;
  const isTied = tiedBidders.length > 1;
  const isLeading = !isTied && batch?.highest_bidder_id === user?.id;
  const userHasBidOnCurrent = !!user && bidHistory.some((b: any) => b.user_id === user.id);
  const isOutbid = userHasBidOnCurrent && !isLeading && !isTied;

  // ─── Loading ───
  if (loading) {
    return <div className="container py-8 px-3 flex items-center justify-center"><div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" /></div>;
  }

  // ─── No Live Lot ───
  if (!batch) {
    return (
      <div className="container py-4 px-3 space-y-4 sm:py-6 sm:px-6">
        <div className="flex items-center gap-2">
          <Gavel className="h-5 w-5 text-primary" />
          <div>
            <h1 className="font-display text-xl font-bold text-foreground">Live Trade</h1>
            <p className="text-xs font-sans text-muted-foreground">
              {isAdmin ? "Manage & control live trades" : "Real-time trade room"}
            </p>
          </div>
        </div>

        {/* Admin: show queue and controls even when no lot is live */}
        {isAdmin && liveSession && queuedBatches.length > 0 && (
          <div className="space-y-3">
            {tradeSummary && (
              <AdminControls
                batch={null} isPaused={false} togglePause={togglePause} updateBatchStatus={updateBatchStatus}
                reducePrice={reducePrice} setReducePrice={setReducePrice} handleReducePrice={handleReducePrice}
                queuedBatches={queuedBatches} hasLiveBatch={false} tradeSummary={tradeSummary} bidCount={0}
              />
            )}
          </div>
        )}

        {!liveSession && (
          <Card>
            <CardContent className="p-8 text-center">
              <Gavel className="h-12 w-12 mx-auto text-muted-foreground/30 mb-3" />
              <p className="font-sans text-muted-foreground">No active trade session</p>
              <p className="text-xs font-sans text-muted-foreground mt-1">
                {isAdmin ? "Start a trade session from the Admin Dashboard" : "Check the schedule for upcoming trades"}
              </p>
            </CardContent>
          </Card>
        )}

        {liveSession && queuedBatches.length === 0 && (
          <Card className="border-2 border-dashed border-border">
            <CardContent className="p-8 text-center">
              <Package className="h-12 w-12 mx-auto text-muted-foreground/30 mb-3" />
              <p className="font-display text-base font-bold text-foreground">No more lots available</p>
              <p className="text-xs font-sans text-muted-foreground mt-1">
                There are no more lots queued for this session.
              </p>
              <p className="text-[11px] font-sans text-muted-foreground mt-2">
                {isAdmin
                  ? "Add a new lot to the queue — a cooling period will start automatically."
                  : "Waiting for the admin to add the next lot."}
              </p>
            </CardContent>
          </Card>
        )}

        {/* Non-admin: session live with queued lots but none yet started — show cooling banner */}
        {!isAdmin && liveSession && queuedBatches.length > 0 && (
          <>
            <Card className="border-2 border-warning bg-warning/5">
              <CardContent className="p-6 text-center">
                <Timer className="h-10 w-10 mx-auto text-warning mb-2 animate-pulse" />
                <p className="font-display text-base font-bold text-foreground">Cooling Period</p>
                <p className="text-xs font-sans text-muted-foreground mt-1">
                  {queuedBatches.length} lot{queuedBatches.length > 1 ? "es" : ""} in queue · Next lot starting shortly
                </p>
              </CardContent>
            </Card>
            <UnifiedBatchList liveBatch={null} queuedBatches={queuedBatches} batchDetails={batchDetails} />
          </>
        )}
      </div>
    );
  }

  // ─── Live Lot Active ───
  return (
    <div className="container py-2 px-3 space-y-2 sm:py-3 sm:px-6 sm:space-y-3">
      {isCooling ? (
        <>
          {/* Inline trade result for participating traders — replaces /bid-result page */}
          {isTrader && !isAdmin && userHasBidOnCurrent && batch && (
            <Card className={`border-2 ${isLeading ? "border-emerald-500 bg-emerald-50" : "border-destructive/40 bg-destructive/5"}`}>
              <CardContent className="p-5 text-center space-y-2">
                <div className={`mx-auto flex h-14 w-14 items-center justify-center rounded-full ${isLeading ? "bg-emerald-500" : "bg-destructive"} text-white shadow-md`}>
                  {isLeading ? <Trophy className="h-7 w-7" /> : <XCircle className="h-7 w-7" />}
                </div>
                <p className="font-display text-2xl font-bold text-foreground">
                  {isLeading ? "You Won!" : "Better Luck Next Time"}
                </p>
                <p className="text-xs font-sans text-muted-foreground">
                  {batch.lot_seq != null ? `Lot #${batch.lot_seq}` : `Lot ${batch.lot_number || ""}`} · Hammer ₹{Number(batch.current_highest_bid || batch.base_price).toLocaleString("en-IN")}/kg
                </p>
                <Badge className={`${isLeading ? "bg-emerald-500" : "bg-muted text-muted-foreground"} text-white border-0`}>
                  {isLeading ? "Winner" : "Not Won"}
                </Badge>
              </CardContent>
            </Card>
          )}
          {/* Shared cooling screen — replaces live card during inter-lot gap */}
          <CoolingScreen
            seconds={coolingSeconds}
            queueCount={queuedBatches.length}
            nextBatchNumber={batch?.lot_number}
          />
          {/* Keep queue/list visible so users can preview what's coming next */}
          {!isAdmin && (
            <UnifiedBatchList liveBatch={null} queuedBatches={queuedBatches} batchDetails={batchDetails} />
          )}
        </>
      ) : (
        <>
          {/* Sticky top: live banner + role-specific bid/control panel */}
          <div className="sticky top-12 z-30 -mx-3 sm:-mx-6 px-3 sm:px-6 pt-1 pb-2 bg-background/95 backdrop-blur-sm space-y-2 border-b border-border/40">
            <LiveBanner batch={batch} currentBid={currentBid} seconds={seconds} bidCount={bidCount} isPaused={isPaused} isCooling={isCooling} coolingSeconds={coolingSeconds} uniqueBidders={new Set(bidHistory.map((b: any) => b.user_id)).size} isOutbid={isOutbid && isTrader && !isAdmin} isLeading={isLeading && isTrader && !isAdmin} bidFlash={bidFlash} gl={batchDetails.gl} moisture={batchDetails.moisture} />

            {isAdmin && (
              <>
                <AdminControls
                  batch={batch} isPaused={isPaused} togglePause={togglePause} updateBatchStatus={updateBatchStatus}
                  reducePrice={reducePrice} setReducePrice={setReducePrice} handleReducePrice={handleReducePrice}
                  queuedBatches={queuedBatches} hasLiveBatch={hasLiveBatch} tradeSummary={tradeSummary} bidCount={bidCount}
                />
                <TiedBidsPicker batch={batch} tiedBidders={tiedBidders} onSelectWinner={selectWinner} />
              </>
            )}

            {isTrader && !isAdmin && !isUnified && batch.seller_id === user?.id && (
              <Card className="border-2 border-warning bg-warning/5">
                <CardContent className="p-4 text-center">
                  <AlertTriangle className="h-5 w-5 text-warning mx-auto mb-1" />
                  <p className="text-sm font-sans font-semibold text-foreground">This is your own lot</p>
                  <p className="text-xs font-sans text-muted-foreground mt-1">You cannot bid on batches you submitted. Watch the trade unfold below.</p>
                </CardContent>
              </Card>
            )}

            {isTrader && !isAdmin && (isUnified || batch.seller_id !== user?.id) && (
              <>
                {profile?.is_blocked && (
                  <Card className="border-2 border-destructive/50" style={{ background: "hsl(0 85% 96%)" }}>
                    <CardContent className="p-3 flex items-center justify-center gap-2 text-center">
                      <AlertTriangle className="h-5 w-5 text-destructive shrink-0" />
                      <div>
                        <p className="text-sm font-sans font-semibold text-destructive">Account has been blocked by Admin</p>
                        <p className="text-xs font-sans text-destructive/80 mt-0.5">Please contact the admin for further details.</p>
                      </div>
                    </CardContent>
                  </Card>
                )}
                {isTied && isPaused && !profile?.is_blocked && (
                  <Card className="border-2 border-warning bg-warning/5">
                    <CardContent className="p-3 flex items-center gap-2">
                      <AlertTriangle className="h-5 w-5 text-warning" />
                      <div>
                        <p className="text-xs font-sans font-semibold text-foreground">Timer paused due to tied highest bid</p>
                        <p className="text-[10px] font-sans text-muted-foreground">{tiedBidders.length} traders tied at ₹{currentBid.toLocaleString("en-IN")}. Admin will select the winner to complete the sale.</p>
                      </div>
                    </CardContent>
                  </Card>
                )}
                {!profile?.is_blocked && (
                  <BidButtons
                    placing={placing || bidCooldown}
                    activeBid={activeBid}
                    placeBid={isApproved ? placeBid : () => toast({ title: "Account pending approval", description: "Contact admin to approve your account before bidding.", variant: "destructive" })}
                    currentBid={currentBid}
                    isPaused={isPaused || isCooling || !isApproved}
                    isCooling={isCooling}
                    coolingSeconds={coolingSeconds}
                    bidIncrements={adminSettings.bid_increments}
                    hasBids={!!batch.highest_bidder_id}
                    isLeading={isLeading}
                    isTied={isTied}
                    batch={batch}
                  />
                )}
              </>
            )}

            {isFarmerOnly && (
              <FarmerStatusCard batch={batch} currentBid={currentBid} />
            )}
          </div>

          {/* Scrollable details below the sticky header */}
          {((isTrader && !isAdmin && (isUnified || batch.seller_id !== user?.id)) || isFarmerOnly || isAdmin) && (
            <BatchDetails batch={batch} details={batchDetails} showDetails={showDetails} setShowDetails={setShowDetails} sellerName={sellerName} winnerName={winnerName} />
          )}

          {isAdmin && (
            <BidHistory bidHistory={bidHistory} bidCount={bidCount} userId={user?.id} uniqueBidders={new Set(bidHistory.map((b: any) => b.user_id)).size} />
          )}

          {!isAdmin && (
            <UnifiedBatchList liveBatch={batch} queuedBatches={queuedBatches} batchDetails={batchDetails} />
          )}
        </>
      )}
    </div>
  );
};

export default LiveTrade;
