import { useState } from 'react';
import { TrendingUp, TrendingDown, ChevronDown, ChevronUp, EyeOff } from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api';
import { cn, fmt } from '@/lib/utils';
import { asDollars } from '@/lib/money';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible';
import type { DriftBill } from '@/types';

function DriftRow({ row, refresh }: { row: DriftBill; refresh: () => void }) {
  const [loading, setLoading] = useState(false);

  async function handleUpdate() {
    setLoading(true);
    const oldAmount = row.expected_amount;
    try {
      await api.updateBill(row.id, { expected_amount: row.recent_amount });
      toast.success(`"${row.name}" updated to ${fmt(row.recent_amount)}`, {
        action: {
          label: 'Undo',
          onClick: async () => {
            try {
              await api.updateBill(row.id, { expected_amount: oldAmount });
              toast.success('Reverted');
              refresh();
            } catch {
              toast.error('Failed to revert');
            }
          },
        },
      });
      refresh();
    } catch {
      toast.error('Failed to update bill');
    } finally {
      setLoading(false);
    }
  }

  async function handleDismiss() {
    setLoading(true);
    try {
      await api.snoozeBillDrift(row.id);
      toast.success('Hidden for 30 days');
      refresh();
    } catch {
      toast.error('Failed to dismiss');
    } finally {
      setLoading(false);
    }
  }

  const isUp = row.direction === 'up';
  const sign = isUp ? '+' : '';

  return (
    <div className="flex flex-wrap items-center gap-x-3 gap-y-2 py-2.5 sm:flex-nowrap">
      {/* Bill info */}
      <div className="flex min-w-0 flex-1 flex-col gap-0.5">
        <div className="flex flex-wrap items-center gap-1.5">
          <span className="truncate text-sm font-medium text-foreground">{row.name}</span>
          {row.category_name && (
            <Badge variant="secondary" className="shrink-0 px-1.5 py-0 text-[10px]">
              {row.category_name}
            </Badge>
          )}
        </div>
        <div className="flex items-center gap-1.5">
          {isUp ? (
            <TrendingUp className="h-3 w-3 text-amber-500 dark:text-amber-400" />
          ) : (
            <TrendingDown className="h-3 w-3 text-teal-500 dark:text-teal-400" />
          )}
          <span
            className={cn(
              'text-xs font-medium',
              isUp ? 'text-amber-600 dark:text-amber-400' : 'text-teal-600 dark:text-teal-400',
            )}
          >
            {sign}
            {row.drift_pct}% over {row.months_sampled} months
          </span>
        </div>
      </div>

      {/* Amount change */}
      <div className="flex shrink-0 items-center gap-1.5">
        <span className="font-mono text-xs text-muted-foreground line-through">
          {fmt(row.expected_amount)}
        </span>
        <span className="text-muted-foreground">→</span>
        <span
          className={cn(
            'font-mono text-sm font-semibold',
            isUp ? 'text-amber-500 dark:text-amber-400' : 'text-teal-500 dark:text-teal-400',
          )}
        >
          {fmt(row.recent_amount)}
        </span>
        <span
          className={cn(
            'rounded-full px-1.5 py-0.5 text-[10px] font-bold leading-none',
            isUp
              ? 'bg-amber-500/15 text-amber-700 dark:text-amber-300'
              : 'bg-teal-500/15 text-teal-700 dark:text-teal-300',
          )}
        >
          {sign}
          {row.drift_pct}%
        </span>
      </div>

      {/* Actions */}
      <div className="flex shrink-0 items-center gap-1">
        <Button
          size="sm"
          variant="outline"
          className={cn(
            'h-7 gap-1.5 px-2.5 text-xs',
            isUp
              ? 'border-amber-400/40 text-amber-600 hover:border-amber-400/70 hover:bg-amber-500/8 hover:text-amber-500 dark:text-amber-400'
              : 'border-teal-400/40 text-teal-600 hover:border-teal-400/70 hover:bg-teal-500/8 hover:text-teal-500 dark:text-teal-400',
          )}
          disabled={loading}
          onClick={handleUpdate}
        >
          Update to {fmt(row.recent_amount)}
        </Button>
        <Button
          size="sm"
          variant="ghost"
          className="h-7 px-2.5 text-xs text-muted-foreground hover:text-foreground"
          disabled={loading}
          onClick={handleDismiss}
        >
          Dismiss
        </Button>
      </div>
    </div>
  );
}

interface DriftInsightPanelProps {
  driftBills?: DriftBill[];
  refresh: () => void;
  // Controlled + persisted collapse state (falls back to local state when omitted).
  collapsed?: boolean;
  onCollapsedChange?: (collapsed: boolean) => void;
  // Fully hide the panel (writes the tracker_show_* setting on the page).
  onHide?: () => void;
}

export default function DriftInsightPanel({
  driftBills,
  refresh,
  collapsed,
  onCollapsedChange,
  onHide,
}: DriftInsightPanelProps) {
  const [localOpen, setLocalOpen] = useState(true);
  const isControlled = collapsed !== undefined;
  const isOpen = isControlled ? !collapsed : localOpen;
  const setOpen = (open: boolean) => {
    if (isControlled) onCollapsedChange?.(!open);
    else setLocalOpen(open);
  };

  if (!driftBills?.length) return null;

  const totalNetDelta = driftBills.reduce(
    (sum, b) => sum + (b.recent_amount - b.expected_amount),
    0,
  );
  const sign = totalNetDelta >= 0 ? '+' : '';
  const netColor =
    totalNetDelta >= 0 ? 'text-amber-500 dark:text-amber-400' : 'text-teal-500 dark:text-teal-400';
  const hasIncrease = driftBills.some((b) => b.direction === 'up');

  const ToggleIcon = isOpen ? ChevronDown : ChevronUp;

  return (
    <Collapsible open={isOpen} onOpenChange={setOpen}>
      <div className="rounded-xl border border-amber-400/30 bg-amber-500/6 shadow-sm overflow-hidden dark:bg-amber-400/5">
        {/* Header */}
        <div className="flex items-center gap-2 px-4 py-3">
          <CollapsibleTrigger asChild>
            <button
              type="button"
              aria-expanded={isOpen}
              className="group flex min-w-0 flex-1 items-center gap-2.5 rounded-md text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-400/40"
            >
              {hasIncrease ? (
                <TrendingUp className="h-4 w-4 shrink-0 text-amber-400" />
              ) : (
                <TrendingDown className="h-4 w-4 shrink-0 text-teal-400" />
              )}
              <span className="text-sm font-semibold text-foreground">
                {driftBills.length === 1
                  ? '1 bill changed price'
                  : `${driftBills.length} bills changed price`}
              </span>
              <span className={cn('font-mono text-sm', netColor)}>
                {sign}
                {fmt(asDollars(Math.abs(totalNetDelta)))}/mo net
              </span>
              <ToggleIcon className="ml-auto h-4 w-4 shrink-0 text-muted-foreground transition-colors group-hover:text-foreground" />
            </button>
          </CollapsibleTrigger>
          {onHide && (
            <Button
              type="button"
              size="sm"
              variant="ghost"
              onClick={onHide}
              className="h-8 shrink-0 gap-1.5 px-2.5 text-xs text-muted-foreground hover:text-foreground"
              aria-label="Hide price-change insights"
            >
              <EyeOff className="h-3.5 w-3.5" />
              <span className="hidden sm:inline">Hide</span>
            </Button>
          )}
        </div>

        {/* Bill rows */}
        <CollapsibleContent>
          <div className="divide-y divide-border/40 px-4 pb-2">
            {driftBills.map((row) => (
              <DriftRow key={row.id} row={row} refresh={refresh} />
            ))}
          </div>
        </CollapsibleContent>
      </div>
    </Collapsible>
  );
}
