import * as React from 'react'

import { cn } from './utils'

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

export interface RuleCondition {
  id: string
  field: string
  operator: string
  value: string | number | boolean
  type?: 'string' | 'number' | 'boolean' | 'date'
}

export interface RuleGroup {
  id: string
  logic: 'AND' | 'OR'
  conditions: (RuleCondition | RuleGroup)[]
}

export interface FieldDefinition {
  name: string
  label: string
  type: 'string' | 'number' | 'boolean' | 'date'
  operators?: string[]
}

export interface RuleEditorProps extends Omit<React.ComponentProps<'div'>, 'onChange'> {
  rules: RuleGroup
  fields: FieldDefinition[]
  onChange?: (rules: RuleGroup) => void
  maxDepth?: number
}

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

const DEFAULT_OPERATORS: Record<string, string[]> = {
  string: [
    'equals',
    'not equals',
    'contains',
    'starts with',
    'ends with',
    'is empty',
    'is not empty',
  ],
  number: [
    'equals',
    'not equals',
    'greater than',
    'less than',
    'greater or equal',
    'less or equal',
    'between',
  ],
  boolean: ['equals', 'not equals'],
  date: ['equals', 'before', 'after', 'between', 'in last', 'is empty'],
}

function isRuleGroup(item: RuleCondition | RuleGroup): item is RuleGroup {
  return 'logic' in item && 'conditions' in item
}

let idCounter = 0
function randomId(): string {
  idCounter++
  return `rule-${Date.now()}-${idCounter}`
}

function getOperatorsForField(field: FieldDefinition): string[] {
  if (field.operators && field.operators.length > 0) return field.operators
  return DEFAULT_OPERATORS[field.type] ?? ['equals']
}

function getDefaultValue(type: string): string | number | boolean {
  if (type === 'number') return 0
  if (type === 'boolean') return true
  if (type === 'date') return new Date().toISOString().split('T')[0] ?? ''
  return ''
}

function cloneGroup(group: RuleGroup): RuleGroup {
  return {
    id: group.id,
    logic: group.logic,
    conditions: group.conditions.map(item => (isRuleGroup(item) ? cloneGroup(item) : { ...item })),
  }
}

// ---------------------------------------------------------------------------
// Condition row
// ---------------------------------------------------------------------------

interface ConditionRowProps {
  condition: RuleCondition
  fields: FieldDefinition[]
  onChange: (updated: RuleCondition) => void
  onRemove: () => void
}

function ConditionRow({ condition, fields, onChange, onRemove }: ConditionRowProps) {
  const fieldDef = fields.find(f => f.name === condition.field)
  const operators = fieldDef ? getOperatorsForField(fieldDef) : ['equals']

  const handleFieldChange = (fieldName: string) => {
    const newFieldDef = fields.find(f => f.name === fieldName)
    if (!newFieldDef) return
    const ops = getOperatorsForField(newFieldDef)
    onChange({
      ...condition,
      field: fieldName,
      type: newFieldDef.type,
      operator: ops[0] ?? 'equals',
      value: getDefaultValue(newFieldDef.type),
    })
  }

  return (
    <div className="bg-glass border-border-glass flex items-center gap-2 rounded-md border p-2 backdrop-blur-[20px]">
      {/* Drag handle */}
      <span className="text-foreground-secondary cursor-grab text-sm" title="Drag to reorder">
        {'\u2261'}
      </span>

      {/* Field select */}
      <select
        className="bg-surface-secondary text-foreground rounded px-2 py-1 text-sm outline-none"
        value={condition.field}
        onChange={e => handleFieldChange(e.target.value)}
      >
        {fields.map(f => (
          <option key={f.name} value={f.name}>
            {f.label}
          </option>
        ))}
      </select>

      {/* Operator select */}
      <select
        className="bg-surface-secondary text-foreground rounded px-2 py-1 text-sm outline-none"
        value={condition.operator}
        onChange={e => onChange({ ...condition, operator: e.target.value })}
      >
        {operators.map(op => (
          <option key={op} value={op}>
            {op}
          </option>
        ))}
      </select>

      {/* Value input */}
      {condition.type === 'boolean' ? (
        <select
          className="bg-surface-secondary text-foreground rounded px-2 py-1 text-sm outline-none"
          value={String(condition.value)}
          onChange={e => onChange({ ...condition, value: e.target.value === 'true' })}
        >
          <option value="true">true</option>
          <option value="false">false</option>
        </select>
      ) : condition.type === 'number' ? (
        <input
          type="number"
          className="bg-surface-secondary text-foreground w-24 rounded px-2 py-1 text-sm outline-none"
          value={String(condition.value)}
          onChange={e => {
            const parsed = Number(e.target.value)
            onChange({ ...condition, value: Number.isNaN(parsed) ? 0 : parsed })
          }}
        />
      ) : condition.type === 'date' ? (
        <input
          type="date"
          className="bg-surface-secondary text-foreground rounded px-2 py-1 text-sm outline-none"
          value={String(condition.value)}
          onChange={e => onChange({ ...condition, value: e.target.value })}
        />
      ) : (
        <input
          type="text"
          className="bg-surface-secondary text-foreground placeholder:text-foreground-secondary min-w-[120px] rounded px-2 py-1 text-sm outline-none"
          placeholder="Enter value..."
          value={String(condition.value)}
          onChange={e => onChange({ ...condition, value: e.target.value })}
        />
      )}

      {/* Remove button */}
      <button
        onClick={onRemove}
        className="text-foreground-secondary hover:text-accent-rose ml-auto text-sm transition-colors"
        title="Remove condition"
      >
        {'\u00D7'}
      </button>
    </div>
  )
}

// ---------------------------------------------------------------------------
// Group component
// ---------------------------------------------------------------------------

interface RuleGroupComponentProps {
  group: RuleGroup
  fields: FieldDefinition[]
  depth: number
  maxDepth: number
  onChange: (updated: RuleGroup) => void
  onRemove?: () => void
}

function RuleGroupComponent({
  group,
  fields,
  depth,
  maxDepth,
  onChange,
  onRemove,
}: RuleGroupComponentProps) {
  const toggleLogic = () => {
    onChange({ ...group, logic: group.logic === 'AND' ? 'OR' : 'AND' })
  }

  const addCondition = () => {
    const firstField = fields[0]
    if (!firstField) return
    const ops = getOperatorsForField(firstField)
    const newCondition: RuleCondition = {
      id: randomId(),
      field: firstField.name,
      operator: ops[0] ?? 'equals',
      value: getDefaultValue(firstField.type),
      type: firstField.type,
    }
    onChange({
      ...group,
      conditions: [...group.conditions, newCondition],
    })
  }

  const addGroup = () => {
    const newGroup: RuleGroup = {
      id: randomId(),
      logic: 'AND',
      conditions: [],
    }
    onChange({
      ...group,
      conditions: [...group.conditions, newGroup],
    })
  }

  const updateItem = (index: number, updated: RuleCondition | RuleGroup) => {
    const newConditions = [...group.conditions]
    newConditions[index] = updated
    onChange({ ...group, conditions: newConditions })
  }

  const removeItem = (index: number) => {
    const newConditions = group.conditions.filter((_, i) => i !== index)
    onChange({ ...group, conditions: newConditions })
  }

  return (
    <div
      className={cn(
        'rounded-lg border p-3',
        depth === 0
          ? 'border-border-glass bg-glass backdrop-blur-[20px]'
          : 'border-border-glass/50 bg-surface-secondary/30'
      )}
    >
      {/* Header */}
      <div className="mb-2 flex items-center gap-2">
        <button
          onClick={toggleLogic}
          className={cn(
            'rounded px-2.5 py-1 text-xs font-bold transition-colors',
            group.logic === 'AND'
              ? 'bg-accent-cyan/20 text-accent-cyan'
              : 'bg-accent-violet/20 text-accent-violet'
          )}
        >
          {group.logic}
        </button>
        <button
          onClick={addCondition}
          className="bg-surface-secondary text-foreground-secondary hover:text-foreground rounded px-2 py-1 text-xs transition-colors"
        >
          + Condition
        </button>
        {depth < maxDepth - 1 && (
          <button
            onClick={addGroup}
            className="bg-surface-secondary text-foreground-secondary hover:text-foreground rounded px-2 py-1 text-xs transition-colors"
          >
            + Group
          </button>
        )}
        {onRemove && (
          <button
            onClick={onRemove}
            className="text-foreground-secondary hover:text-accent-rose ml-auto text-sm transition-colors"
            title="Remove group"
          >
            {'\u00D7'}
          </button>
        )}
      </div>

      {/* Conditions */}
      <div className="flex flex-col gap-2">
        {group.conditions.map((item, index) =>
          isRuleGroup(item) ? (
            <RuleGroupComponent
              key={item.id}
              group={item}
              fields={fields}
              depth={depth + 1}
              maxDepth={maxDepth}
              onChange={updated => updateItem(index, updated)}
              onRemove={() => removeItem(index)}
            />
          ) : (
            <ConditionRow
              key={item.id}
              condition={item}
              fields={fields}
              onChange={updated => updateItem(index, updated)}
              onRemove={() => removeItem(index)}
            />
          )
        )}
      </div>
    </div>
  )
}

// ---------------------------------------------------------------------------
// RuleEditor
// ---------------------------------------------------------------------------

function RuleEditor({
  rules,
  fields,
  onChange,
  maxDepth = 3,
  className,
  ...props
}: RuleEditorProps) {
  const [currentRules, setCurrentRules] = React.useState(() => cloneGroup(rules))

  // Sync with external rules prop
  React.useEffect(() => {
    setCurrentRules(cloneGroup(rules))
  }, [rules])

  const handleChange = React.useCallback(
    (updated: RuleGroup) => {
      setCurrentRules(updated)
      onChange?.(cloneGroup(updated))
    },
    [onChange]
  )

  return (
    <div data-slot="rule-editor" className={cn(className)} {...props}>
      <RuleGroupComponent
        group={currentRules}
        fields={fields}
        depth={0}
        maxDepth={maxDepth}
        onChange={handleChange}
      />
    </div>
  )
}
RuleEditor.displayName = 'RuleEditor'

export { RuleEditor }
