/**
 * Visual drag-and-drop strategy rule builder using @dnd-kit.
 * Lets users compose IF/THEN trading rules without writing code.
 */
import { useState, useCallback, useEffect, useRef } from 'react';
import type { ChangeEvent } from 'react';
import {
  DndContext,
  closestCenter,
  PointerSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
} from '@dnd-kit/core';
import {
  SortableContext,
  verticalListSortingStrategy,
  useSortable,
  arrayMove,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { GripVertical, Plus, Trash2, Save, Play } from 'lucide-react';
import { Card, CardContent } from '../ui/card';
import { Button, IconButton, Input, Select } from '../ui/Primitives';

// ─── Types ────────────────────────────────────────────────────────────────────
export type Indicator   = 'RSI' | 'MACD' | 'EMA_50' | 'EMA_200' | 'Price' | 'Volume';
export type Condition   = 'above' | 'below' | 'crosses_above' | 'crosses_below';
export type TradeAction = 'BUY' | 'SELL';
export type QtyType     = 'shares' | 'percent';

export interface VisualRule {
  id:           string;
  indicator:    Indicator;
  condition:    Condition;
  value:        number;
  action:       TradeAction;
  quantity:     number;
  quantityType: QtyType;
}

interface Props {
  symbol:   string;
  onSave:   (name: string, rules: VisualRule[]) => Promise<void>;
  onBacktest?: (rules: VisualRule[]) => void;
}

// ─── Helpers ─────────────────────────────────────────────────────────────────
const INDICATOR_DEFAULTS: Record<Indicator, number> = {
  RSI: 30, MACD: 0, EMA_50: 150, EMA_200: 150, Price: 100, Volume: 1000000,
};

const INDICATOR_LABELS: Record<Indicator, string> = {
  RSI: 'RSI (14)', MACD: 'MACD Signal', EMA_50: 'EMA 50',
  EMA_200: 'EMA 200', Price: 'Price ($)', Volume: 'Volume',
};

const CONDITION_LABELS: Record<Condition, string> = {
  above:         'is above',
  below:         'is below',
  crosses_above: 'crosses above',
  crosses_below: 'crosses below',
};

let _uid = 0;
const uid = () => `rule_${++_uid}_${Date.now()}`;

function makeRule(): VisualRule {
  return {
    id: uid(), indicator: 'RSI', condition: 'below',
    value: 30, action: 'BUY', quantity: 10, quantityType: 'shares',
  };
}

// ─── Sortable rule card ───────────────────────────────────────────────────────
function RuleCard({
  rule,
  index,
  onChange,
  onDelete,
}: {
  rule:     VisualRule;
  index:    number;
  onChange: (id: string, patch: Partial<VisualRule>) => void;
  onDelete: (id: string) => void;
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } =
    useSortable({ id: rule.id });

  const style: React.CSSProperties = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.55 : 1,
    background: 'var(--card)',
    border: '1px solid var(--border)',
    borderRadius: 14,
    padding: '12px 14px',
    display: 'flex',
    alignItems: 'center',
    gap: 10,
    marginBottom: 8,
    boxShadow: isDragging ? 'var(--card-shadow)' : undefined,
  };

  const sel: React.CSSProperties = {
    border: '1px solid var(--border)', borderRadius: 10, padding: '6px 10px',
    fontSize: 12, background: 'var(--input)', cursor: 'pointer', color: 'var(--foreground)',
    fontFamily: 'inherit',
  };
  const numInp: React.CSSProperties = {
    ...sel, width: 70, textAlign: 'right',
  };

  return (
    <div ref={setNodeRef} style={style}>
      {/* Drag handle */}
      <div
        {...attributes}
        {...listeners}
        style={{ cursor: 'grab', color: 'var(--bl-text-faint)', flexShrink: 0, touchAction: 'none' }}
      >
        <GripVertical size={16} />
      </div>

      {/* Rule label */}
      <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--bl-text-faint)', width: 22, flexShrink: 0 }}>
        #{index + 1}
      </span>

      {/* IF */}
      <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--bl-text-quiet)' }}>IF</span>

      {/* Indicator */}
      <Select
        value={rule.indicator}
        style={sel}
        controlSize="sm"
        variant="surface"
        options={(Object.keys(INDICATOR_LABELS) as Indicator[]).map(k => ({ value: k, label: INDICATOR_LABELS[k] }))}
        onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, {
          indicator: e.target.value as Indicator,
          value: INDICATOR_DEFAULTS[e.target.value as Indicator],
        })}
      />

      {/* Condition */}
      <Select
        value={rule.condition}
        style={sel}
        controlSize="sm"
        variant="surface"
        options={(Object.keys(CONDITION_LABELS) as Condition[]).map(k => ({ value: k, label: CONDITION_LABELS[k] }))}
        onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, { condition: e.target.value as Condition })}
      />

      {/* Value */}
      <Input
        type="number"
        value={rule.value}
        style={numInp}
        controlSize="sm"
        variant="surface"
        onChange={(e: ChangeEvent<HTMLInputElement>) => onChange(rule.id, { value: parseFloat(e.target.value) || 0 })}
      />

      {/* THEN */}
      <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--bl-text-quiet)' }}>→</span>

      {/* Action */}
      <Select value={rule.action} style={{
        ...sel,
        color: rule.action === 'BUY' ? 'var(--bl-success)' : 'var(--bl-danger)',
        fontWeight: 700,
        background: rule.action === 'BUY' ? 'var(--bl-success-muted)' : 'var(--bl-danger-muted)',
        border: `1px solid ${rule.action === 'BUY' ? 'var(--bl-success)' : 'var(--bl-danger)'}`,
      }}
        controlSize="sm"
        variant="surface"
        options={[
          { value: 'BUY', label: 'BUY' },
          { value: 'SELL', label: 'SELL' },
        ]}
        onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, { action: e.target.value as TradeAction })}
      />

      {/* Quantity */}
      <Input
        type="number"
        value={rule.quantity}
        style={numInp}
        min={1}
        controlSize="sm"
        variant="surface"
        onChange={(e: ChangeEvent<HTMLInputElement>) => onChange(rule.id, { quantity: parseFloat(e.target.value) || 1 })}
      />

      {/* Qty type */}
      <Select
        value={rule.quantityType}
        style={sel}
        controlSize="sm"
        variant="surface"
        options={[
          { value: 'shares', label: 'shares' },
          { value: 'percent', label: '% of capital' },
        ]}
        onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, { quantityType: e.target.value as QtyType })}
      />

      {/* Delete */}
      <IconButton
        type="button"
        label="Remove rule"
        icon={<Trash2 size={14} />}
        onClick={() => onDelete(rule.id)}
        style={{
          marginLeft: 'auto', background: 'none', border: 'none',
          cursor: 'pointer', color: 'var(--bl-text-faint)', padding: 4, borderRadius: 6,
          display: 'flex', alignItems: 'center',
          flexShrink: 0,
        }}
      />
    </div>
  );
}

// ─── VisualRuleBuilder ────────────────────────────────────────────────────────
export function VisualRuleBuilder({ symbol, onSave, onBacktest }: Props) {
  const [rules,    setRules]    = useState<VisualRule[]>([makeRule()]);
  const [name,     setName]     = useState('My Strategy');
  const [saving,   setSaving]   = useState(false);
  const [savedMsg, setSavedMsg] = useState('');
  const mountedRef = useRef(true);
  const savedMessageTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const clearSavedMessageTimeout = useCallback(() => {
    if (savedMessageTimeoutRef.current) {
      clearTimeout(savedMessageTimeoutRef.current);
      savedMessageTimeoutRef.current = null;
    }
  }, []);

  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
      clearSavedMessageTimeout();
    };
  }, [clearSavedMessageTimeout]);

  const sensors = useSensors(useSensor(PointerSensor, {
    activationConstraint: { distance: 5 },
  }));

  const handleDragEnd = useCallback((event: DragEndEvent) => {
    const { active, over } = event;
    if (over && active.id !== over.id) {
      setRules(prev => {
        const from = prev.findIndex(r => r.id === active.id);
        const to   = prev.findIndex(r => r.id === over.id);
        return arrayMove(prev, from, to);
      });
    }
  }, []);

  const handleChange = useCallback((id: string, patch: Partial<VisualRule>) => {
    setRules(prev => prev.map(r => r.id === id ? { ...r, ...patch } : r));
  }, []);

  const handleDelete = useCallback((id: string) => {
    setRules(prev => prev.filter(r => r.id !== id));
  }, []);

  const handleSave = async () => {
    if (!name.trim() || rules.length === 0) return;
    setSaving(true);
    try {
      await onSave(name.trim(), rules);
      if (!mountedRef.current) return;
      setSavedMsg('Strategy saved!');
      clearSavedMessageTimeout();
      savedMessageTimeoutRef.current = setTimeout(() => {
        if (mountedRef.current) {
          setSavedMsg('');
        }
        savedMessageTimeoutRef.current = null;
      }, 3000);
    } catch {
      if (mountedRef.current) {
        setSavedMsg('Save failed — try again');
      }
    } finally {
      if (mountedRef.current) {
        setSaving(false);
      }
    }
  };

  const handleShortcut = (event: React.KeyboardEvent<HTMLDivElement>) => {
    if (!(event.metaKey || event.ctrlKey)) return;

    if (event.key.toLowerCase() === 's') {
      event.preventDefault();
      if (!saving && rules.length > 0) void handleSave();
    } else if (event.key === 'Enter' && onBacktest) {
      event.preventDefault();
      onBacktest(rules);
    }
  };

  return (
    <div onKeyDownCapture={handleShortcut}>
      {/* Header row */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 20 }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 500, marginBottom: 3 }}>Strategy name</div>
          <Input
            value={name}
            onChange={(e: ChangeEvent<HTMLInputElement>) => setName(e.target.value)}
            controlSize="sm"
            variant="surface"
            style={{
              border: '1px solid var(--border)', borderRadius: 12,
              padding: '7px 12px', fontSize: 14, fontWeight: 600,
              color: 'var(--foreground)', background: 'var(--input)', fontFamily: 'inherit',
              outline: 'none', width: 260,
            }}
          />
        </div>
        <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 8 }}>
          {savedMsg && (
            <span style={{ fontSize: 12, color: 'var(--primary)', fontWeight: 600 }}>{savedMsg}</span>
          )}
          {onBacktest && (
            <Button
              onClick={() => onBacktest(rules)}
              title="Run visual strategy backtest (Cmd/Ctrl+Enter)"
              variant="outline"
              size="sm"
            >
              <Play size={13} /> Run Backtest
            </Button>
          )}
          <Button
            onClick={handleSave}
            disabled={saving || rules.length === 0}
            title="Save visual strategy (Cmd/Ctrl+S)"
            size="sm"
          >
            <Save size={13} /> {saving ? 'Saving…' : 'Save Strategy'}
          </Button>
        </div>
      </div>

      {/* Column headers */}
      <div style={{
        display: 'flex', gap: 10, paddingLeft: 58, paddingRight: 40,
        fontSize: 10, fontWeight: 700, color: 'var(--muted-foreground)', textTransform: 'uppercase',
        letterSpacing: '0.05em', marginBottom: 6,
      }}>
        <span style={{ flex: 1 }}>IF Indicator</span>
        <span style={{ flex: 1 }}>Condition</span>
        <span style={{ width: 70 }}>Value</span>
        <span style={{ width: 16 }} />
        <span style={{ width: 60 }}>Action</span>
        <span style={{ width: 70 }}>Qty</span>
        <span style={{ width: 100 }}>Type</span>
      </div>

      {/* Drag-and-drop rule list */}
      <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
        <SortableContext items={rules.map(r => r.id)} strategy={verticalListSortingStrategy}>
          {rules.map((rule, i) => (
            <RuleCard
              key={rule.id}
              rule={rule}
              index={i}
              onChange={handleChange}
              onDelete={handleDelete}
            />
          ))}
        </SortableContext>
      </DndContext>

      {/* Add rule */}
      <Button
        type="button"
        onClick={() => setRules(prev => [...prev, makeRule()])}
        variant="outline"
        size="sm"
        style={{
          display: 'flex', alignItems: 'center', gap: 7,
          width: '100%', padding: '10px 0', border: '1px dashed var(--border-strong)',
          borderRadius: 14, background: 'transparent', color: 'var(--muted-foreground)',
          fontSize: 13, fontWeight: 600, cursor: 'pointer', justifyContent: 'center',
          marginTop: 4,
        }}
      >
        <Plus size={15} /> Add Rule
      </Button>

      {/* Rule summary */}
      {rules.length > 0 && (
        <Card className="mt-5 border-[var(--ring)]/20 bg-[var(--accent-soft)]">
          <CardContent className="px-4 py-4">
          <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ring)', marginBottom: 6 }}>
            Strategy Preview — {symbol}
          </div>
          {rules.map((r, i) => (
            <div key={r.id} style={{ fontSize: 12, color: 'var(--foreground)', marginBottom: 3 }}>
              {i + 1}. IF {INDICATOR_LABELS[r.indicator]} {CONDITION_LABELS[r.condition]} {r.value}
              {' → '}{r.action} {r.quantity} {r.quantityType === 'percent' ? `% of capital` : 'shares'}
            </div>
          ))}
          </CardContent>
        </Card>
      )}
    </div>
  );
}
