import { useState, useMemo, useEffect, useCallback } from 'react';
import {
  Modal, FormField, Input, Select, Textarea, Toggle, Button, Collapsible, ConfirmDialog,
} from '@cameleer/design-system';
import type { TapDefinition, ApplicationConfig } from '../api/queries/commands';
import { useTestExpression } from '../api/queries/commands';
import styles from './TapConfigModal.module.css';

const LANGUAGE_OPTIONS = [
  { value: 'simple', label: 'Simple' },
  { value: 'jsonpath', label: 'JSONPath' },
  { value: 'xpath', label: 'XPath' },
  { value: 'jq', label: 'jq' },
  { value: 'groovy', label: 'Groovy' },
];

const TARGET_OPTIONS = [
  { value: 'INPUT', label: 'Input' },
  { value: 'OUTPUT', label: 'Output' },
  { value: 'BOTH', label: 'Both' },
];

const TYPE_CHOICES: Array<{ value: TapDefinition['attributeType']; label: string; tooltip: string }> = [
  { value: 'BUSINESS_OBJECT', label: 'Business Object', tooltip: 'A key business identifier like orderId, customerId, or invoiceNumber' },
  { value: 'CORRELATION', label: 'Correlation', tooltip: 'Used to correlate related exchanges across routes or services' },
  { value: 'EVENT', label: 'Event', tooltip: 'Marks a business event occurrence like orderPlaced or paymentReceived' },
  { value: 'CUSTOM', label: 'Custom', tooltip: 'General-purpose attribute for any other extraction need' },
];

interface ProcessorOption {
  value: string;
  label: string;
}

export interface TapConfigModalProps {
  open: boolean;
  onClose: () => void;
  /** Tap to edit, or null for creating a new tap */
  tap: TapDefinition | null;
  /** Processor options for the dropdown (id + label) */
  processorOptions: ProcessorOption[];
  /** Pre-selected processor ID (used when opening from diagram context menu) */
  defaultProcessorId?: string;
  /** Application name (for test expression API) */
  application: string;
  /** Environment slug (for test expression API) */
  environment: string;
  /** Current application config (taps array will be modified) */
  config: ApplicationConfig;
  /** Called with the updated config to persist */
  onSave: (config: ApplicationConfig) => void;
  /** Called to delete the tap */
  onDelete?: (tap: TapDefinition) => void;
}

export function TapConfigModal({
  open, onClose, tap, processorOptions, defaultProcessorId,
  application, environment, config, onSave, onDelete,
}: TapConfigModalProps) {
  const isEdit = !!tap;

  const [name, setName] = useState('');
  const [processor, setProcessor] = useState('');
  const [language, setLanguage] = useState('simple');
  const [target, setTarget] = useState<'INPUT' | 'OUTPUT' | 'BOTH'>('OUTPUT');
  const [expression, setExpression] = useState('');
  const [attrType, setAttrType] = useState<TapDefinition['attributeType']>('BUSINESS_OBJECT');
  const [enabled, setEnabled] = useState(true);

  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
  const [testTab, setTestTab] = useState('custom');
  const [testPayload, setTestPayload] = useState('');
  const [testResult, setTestResult] = useState<{ result?: string; error?: string } | null>(null);
  const testMutation = useTestExpression();

  // Reset form when modal opens
  const [lastOpen, setLastOpen] = useState(false);
  if (open && !lastOpen) {
    if (tap) {
      setName(tap.attributeName);
      setProcessor(tap.processorId);
      setLanguage(tap.language);
      setTarget(tap.target);
      setExpression(tap.expression);
      setAttrType(tap.attributeType);
      setEnabled(tap.enabled);
    } else {
      setName('');
      setProcessor(defaultProcessorId ?? processorOptions[0]?.value ?? '');
      setLanguage('simple');
      setTarget('OUTPUT');
      setExpression('');
      setAttrType('BUSINESS_OBJECT');
      setEnabled(true);
    }
    setTestResult(null);
    setTestPayload('');
  }
  if (open !== lastOpen) setLastOpen(open);

  function handleSave() {
    const tapDef: TapDefinition = {
      tapId: tap?.tapId || `tap-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
      processorId: processor,
      target,
      expression,
      language,
      attributeName: name,
      attributeType: attrType,
      enabled,
      version: tap ? tap.version + 1 : 1,
    };
    const taps = tap
      ? config.taps.map(t => t.tapId === tap.tapId ? tapDef : t)
      : [...(config.taps || []), tapDef];
    onSave({ ...config, taps });
    onClose();
  }

  function handleDelete() {
    if (tap && onDelete) {
      onDelete(tap);
      onClose();
      setShowDeleteConfirm(false);
    }
  }

  function handleTest() {
    testMutation.mutate(
      { application, environment, expression, language, body: testPayload, target },
      {
        onSuccess: (data) => setTestResult(data),
        onError: (err) => setTestResult({ error: (err as Error).message }),
      },
    );
  }

  // Processor options with fallback if the current processor isn't in the list
  const allOptions = useMemo(() => {
    if (processor && !processorOptions.find(p => p.value === processor)) {
      return [{ value: processor, label: processor }, ...processorOptions];
    }
    return processorOptions;
  }, [processorOptions, processor]);

  // Close only on ESC key, not on backdrop click.
  // Modal calls onClose for both — pass a no-op, handle ESC ourselves.
  const handleEsc = useCallback((e: KeyboardEvent) => {
    if (e.key === 'Escape') onClose();
  }, [onClose]);
  useEffect(() => {
    if (!open) return;
    document.addEventListener('keydown', handleEsc);
    return () => document.removeEventListener('keydown', handleEsc);
  }, [open, handleEsc]);

  return (
    <Modal open={open} onClose={() => {}} title={isEdit ? 'Edit Tap' : 'Add Tap'} size="lg">
      <div className={styles.body}>
        <FormField label="Attribute Name">
          <Input value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. orderId" />
        </FormField>

        <FormField label="Processor">
          <Select
            options={allOptions}
            value={processor}
            onChange={(e) => setProcessor(e.target.value)}
          />
        </FormField>

        <div className={styles.formRow}>
          <FormField label="Language">
            <Select
              options={LANGUAGE_OPTIONS}
              value={language}
              onChange={(e) => setLanguage(e.target.value)}
            />
          </FormField>
          <FormField label="Target">
            <Select
              options={TARGET_OPTIONS}
              value={target}
              onChange={(e) => setTarget(e.target.value as 'INPUT' | 'OUTPUT' | 'BOTH')}
            />
          </FormField>
        </div>

        <FormField label="Expression">
          <Textarea
            className={styles.monoTextarea}
            value={expression}
            onChange={(e) => setExpression(e.target.value)}
            placeholder="e.g. ${body.orderId}"
            rows={3}
          />
        </FormField>

        <FormField label="Type">
          <div className={styles.typeSelector}>
            {TYPE_CHOICES.map(tc => (
              <button
                key={tc.value}
                type="button"
                title={tc.tooltip}
                className={`${styles.typeOption} ${attrType === tc.value ? styles.typeOptionActive : ''}`}
                onClick={() => setAttrType(tc.value)}
              >
                {tc.label}
              </button>
            ))}
          </div>
        </FormField>

        <div className={styles.formRow}>
          <FormField label="Enabled">
            <Toggle checked={enabled} onChange={() => setEnabled(!enabled)} />
          </FormField>
        </div>

        <Collapsible title="Test Expression">
          <div className={styles.testSection}>
            <div className={styles.testBody}>
              <Textarea
                className={styles.monoTextarea}
                value={testPayload}
                onChange={(e) => setTestPayload(e.target.value)}
                placeholder='{"orderId": "12345", ...}'
                rows={4}
              />
            </div>

            <div className={styles.testBody}>
              <Button
                variant="secondary"
                size="sm"
                onClick={handleTest}
                loading={testMutation.isPending}
                disabled={!expression}
              >
                Test
              </Button>
            </div>

            {testResult && (
              <div className={`${styles.testResult} ${testResult.error ? styles.testError : styles.testSuccess}`}>
                {testResult.error ?? testResult.result ?? 'No result'}
              </div>
            )}
          </div>
        </Collapsible>

        <div className={styles.footer}>
          {isEdit && onDelete && (
            <div className={styles.footerLeft}>
              <Button variant="danger" onClick={() => setShowDeleteConfirm(true)}>Delete</Button>
            </div>
          )}
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button variant="primary" onClick={handleSave} disabled={!name || !processor || !expression}>Save</Button>
        </div>
      </div>

      <ConfirmDialog
        open={showDeleteConfirm}
        onClose={() => setShowDeleteConfirm(false)}
        onConfirm={handleDelete}
        title="Delete Tap"
        message={`Delete tap "${name}"? This will remove the tap from the configuration.`}
        confirmText={name}
        confirmLabel="Delete"
        variant="danger"
      />
    </Modal>
  );
}
