import React, {
  forwardRef,
  useEffect,
  useImperativeHandle,
  useMemo,
  useState,
} from 'react';
import { Alert, Input, message } from 'antd';
import type { WorkflowDSL } from '../types';

const { TextArea } = Input;

const EMPTY_TEMPLATE = '{\n  "nodes": [],\n  "edges": []\n}';

interface DslViewProps {
  dsl: WorkflowDSL | null;
  readonly?: boolean;
  onApply?: (newDsl: WorkflowDSL) => void;
}

export interface DslViewHandle {
  /** Validate textarea and apply to parent. Returns true on success (or no-op when text unchanged), false on validation failure. */
  apply: () => boolean;
  copy: () => Promise<void>;
  /** Whether textarea content differs from last applied DSL. */
  isDirty: () => boolean;
}

function stringifyDsl(dsl: WorkflowDSL | null): string {
  if (!dsl) return EMPTY_TEMPLATE;
  return JSON.stringify(dsl, null, 2);
}

/** 形状级校验：只检查必需字段，深层字段（position/config 等）由画布或保存时暴露 */
function validateDsl(
  parsed: any,
): { ok: true; dsl: WorkflowDSL } | { ok: false; error: string } {
  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
    return { ok: false, error: '根必须是对象 { nodes, edges }' };
  }
  if (!Array.isArray(parsed.nodes)) {
    return { ok: false, error: '字段 nodes 必须是数组' };
  }
  if (!Array.isArray(parsed.edges)) {
    return { ok: false, error: '字段 edges 必须是数组' };
  }
  for (let i = 0; i < parsed.nodes.length; i++) {
    const n = parsed.nodes[i];
    if (!n || typeof n !== 'object') {
      return { ok: false, error: `节点 [${i}] 必须是对象` };
    }
    if (typeof n.id !== 'string' || !n.id) {
      return { ok: false, error: `节点 [${i}] 缺少必需字段：id` };
    }
    if (typeof n.type !== 'string' || !n.type) {
      return { ok: false, error: `节点 [${i}] 缺少必需字段：type` };
    }
  }
  for (let i = 0; i < parsed.edges.length; i++) {
    const e = parsed.edges[i];
    if (!e || typeof e !== 'object') {
      return { ok: false, error: `连线 [${i}] 必须是对象` };
    }
    if (typeof e.id !== 'string' || !e.id) {
      return { ok: false, error: `连线 [${i}] 缺少必需字段：id` };
    }
    if (typeof e.source !== 'string' || !e.source) {
      return { ok: false, error: `连线 [${i}] 缺少必需字段：source` };
    }
    if (typeof e.target !== 'string' || !e.target) {
      return { ok: false, error: `连线 [${i}] 缺少必需字段：target` };
    }
  }
  return { ok: true, dsl: parsed as WorkflowDSL };
}

async function copyToClipboard(text: string): Promise<boolean> {
  try {
    if (navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(text);
      return true;
    }
  } catch {
    // fallthrough
  }
  // Fallback for non-secure context
  try {
    const ta = document.createElement('textarea');
    ta.value = text;
    ta.style.position = 'fixed';
    ta.style.opacity = '0';
    document.body.appendChild(ta);
    ta.select();
    const ok = document.execCommand('copy');
    document.body.removeChild(ta);
    return ok;
  } catch {
    return false;
  }
}

export const DslView = forwardRef<DslViewHandle, DslViewProps>(function DslView(
  { dsl, readonly = false, onApply },
  ref,
) {
  const initial = useMemo(() => stringifyDsl(dsl), [dsl]);
  const [text, setText] = useState(initial);
  const [error, setError] = useState<string | null>(null);

  // dsl prop 变化时重置 text（应用、版本切换、AI 生成等场景）
  useEffect(() => {
    setText(initial);
    setError(null);
  }, [initial]);

  function handleTextChange(next: string) {
    setText(next);
    if (error) setError(null);
  }

  function handleApply(): boolean {
    // 文本未变更：no-op success（无需重复应用，避免无意义重渲染）
    if (text === initial) {
      setError(null);
      return true;
    }
    let parsed: any;
    try {
      parsed = JSON.parse(text);
    } catch (e: any) {
      setError(`JSON 解析失败：${e?.message ?? String(e)}`);
      return false;
    }
    const result = validateDsl(parsed);
    if (!result.ok) {
      setError(result.error);
      return false;
    }
    const normalized = JSON.stringify(result.dsl, null, 2);
    setText(normalized);
    setError(null);
    onApply?.(result.dsl);
    return true;
  }

  async function handleCopy() {
    const ok = await copyToClipboard(text);
    if (ok) {
      message.success('已复制到剪贴板');
    } else {
      message.error('复制失败，请手动选择文本复制');
    }
  }

  useImperativeHandle(
    ref,
    () => ({
      apply: handleApply,
      copy: handleCopy,
      isDirty: () => text !== initial,
    }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [text, initial, onApply],
  );

  return (
    <div
      style={{
        flex: 1,
        display: 'flex',
        flexDirection: 'column',
        minHeight: 0,
        background: '#fff',
        padding: 16,
      }}
    >
      {error && (
        <Alert
          type="error"
          message={error}
          showIcon
          closable
          onClose={() => setError(null)}
          style={{ marginBottom: 8, flexShrink: 0 }}
        />
      )}

      <TextArea
        value={text}
        onChange={(e) => handleTextChange(e.target.value)}
        readOnly={readonly}
        spellCheck={false}
        autoSize={false}
        style={{
          flex: 1,
          fontFamily:
            'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
          fontSize: 13,
          lineHeight: 1.5,
          resize: 'none',
        }}
      />
    </div>
  );
});
