import React, { useMemo, useState } from 'react';
import {
  Alert,
  Button,
  Input,
  Modal,
  Select,
  Space,
  Spin,
  Typography,
  message,
} from 'antd';
import { CheckCircleOutlined, LoadingOutlined } from '@ant-design/icons';
import { useWorkflowAgent } from '../../hooks/useWorkflowAgent';
import type { WorkflowNodeType, NodeInstanceAgentOutput } from '../../types';

const { Text } = Typography;
const { TextArea } = Input;

/**
 * Front-end hardcoded mapping: nodeType category → prompt placeholder & scenario hint.
 */
const CATEGORY_PROMPT_CONFIG: Record<
  string,
  { placeholder: string; scenarioHint: string }
> = {
  TRIGGER: {
    placeholder: 'e.g. Trigger every weekday at 9am Shanghai time',
    scenarioHint:
      'This is a trigger node. Generate config for defining when/how the workflow starts.',
  },
  ACTION: {
    placeholder:
      'e.g. Send a POST request to https://api.example.com/notify with the order data',
    scenarioHint:
      'This is an action node. Generate config for performing an operation (HTTP call, DB query, notification, etc.).',
  },
  CONDITION: {
    placeholder:
      'e.g. Check if order.amount > 1000 AND order.status is "pending"',
    scenarioHint:
      'This is a condition/branching node. Generate config for evaluating conditions to decide the flow path.',
  },
  LOOP: {
    placeholder: 'e.g. Iterate over the "items" array field with concurrency 3',
    scenarioHint:
      'This is a loop node. Generate config for iterating over data collections.',
  },
  FLOW_CONTROL: {
    placeholder: 'e.g. Wait 30 seconds before proceeding to the next step',
    scenarioHint:
      'This is a flow control node. Generate config for managing execution flow (delay, parallel, error handling).',
  },
  APPROVAL: {
    placeholder:
      'e.g. Wait for manager@company.com to approve, timeout after 24 hours',
    scenarioHint:
      'This is an approval node. Generate config for human approval gates with escalation rules.',
  },
  SUB_WORKFLOW: {
    placeholder:
      'e.g. Call the "order-processing" workflow and wait for completion',
    scenarioHint:
      'This is a sub-workflow node. Generate config for invoking another workflow as a child process.',
  },
};

const DEFAULT_PROMPT_CONFIG = {
  placeholder: 'Describe what this node instance should do...',
  scenarioHint: 'Generate appropriate configuration for this node type.',
};

function getPromptConfig(category: string) {
  return CATEGORY_PROMPT_CONFIG[category] || DEFAULT_PROMPT_CONFIG;
}

function tryParseNodeInstanceOutput(
  raw: string,
): NodeInstanceAgentOutput | null {
  try {
    const match = raw.match(/```json\s*([\s\S]*?)```/);
    const jsonStr = match ? match[1].trim() : raw.trim();
    const parsed = JSON.parse(jsonStr);
    if (typeof parsed.name === 'string' && typeof parsed.config === 'object') {
      return parsed as NodeInstanceAgentOutput;
    }
  } catch {
    // not valid
  }
  return null;
}

export interface AiGenerateResult {
  nodeTypeId: string;
  name: string;
  description: string;
  config: Record<string, any>;
}

interface Props {
  open: boolean;
  nodeTypes: WorkflowNodeType[];
  onClose: () => void;
  onApply: (data: AiGenerateResult) => void;
}

export function CreateNodeInstanceModal({
  open,
  nodeTypes,
  onClose,
  onApply,
}: Props) {
  const [selectedNodeTypeId, setSelectedNodeTypeId] = useState<
    string | undefined
  >();
  const [prompt, setPrompt] = useState('');
  const [step, setStep] = useState<'selectType' | 'generating' | 'done'>(
    'selectType',
  );
  const [generatedResult, setGeneratedResult] =
    useState<NodeInstanceAgentOutput | null>(null);
  const [resultInput, setResultInput] = useState('');

  const {
    generate,
    abort: abortAgent,
    loading: agentLoading,
    error: agentError,
  } = useWorkflowAgent({ nodeTypes });

  const selectedNodeType = useMemo(
    () => nodeTypes.find((nt) => String(nt.id) === selectedNodeTypeId),
    [selectedNodeTypeId, nodeTypes],
  );

  const promptConfig = useMemo(
    () =>
      selectedNodeType
        ? getPromptConfig(selectedNodeType.category)
        : DEFAULT_PROMPT_CONFIG,
    [selectedNodeType],
  );

  async function handleGenerate() {
    if (!prompt.trim()) {
      message.warning('Please describe what this node instance should do');
      return;
    }
    if (!selectedNodeType) return;

    setStep('generating');
    const result = await generate({
      action: 'create_node_instance',
      prompt: prompt.trim(),
      nodeType: selectedNodeType,
      scenarioHint: promptConfig.scenarioHint,
    });

    if (result && 'config' in result) {
      const nodeResult = result as NodeInstanceAgentOutput;
      setGeneratedResult(nodeResult);
      setResultInput(JSON.stringify(nodeResult, null, 2));
      setStep('done');
    } else if (!result) {
      // Aborted or still waiting — stay in generating to allow manual paste
      setStep('generating');
    }
  }

  function handleApplyManualJson() {
    const parsed = tryParseNodeInstanceOutput(resultInput);
    if (!parsed) {
      message.error(
        'Invalid JSON format. Expected: { "name": "...", "description": "...", "config": {...} }',
      );
      return;
    }
    setGeneratedResult(parsed);
    setResultInput(JSON.stringify(parsed, null, 2));
    setStep('done');
  }

  function handleConfirm() {
    if (!generatedResult || !selectedNodeTypeId) return;

    onApply({
      nodeTypeId: selectedNodeTypeId,
      name: generatedResult.name,
      description: generatedResult.description || '',
      config: generatedResult.config,
    });
    handleClose();
  }

  function handleClose() {
    abortAgent();
    setSelectedNodeTypeId(undefined);
    setPrompt('');
    setStep('selectType');
    setGeneratedResult(null);
    setResultInput('');
    onClose();
  }

  return (
    <Modal
      title="AI Create Node Instance"
      open={open}
      onCancel={handleClose}
      footer={null}
      destroyOnClose
      width={560}
    >
      <Space direction="vertical" style={{ width: '100%' }} size="middle">
        {/* Node Type Select — always visible */}
        <div>
          <Text strong>Node Type</Text>
          <Select
            placeholder="Select a node type"
            value={selectedNodeTypeId}
            onChange={setSelectedNodeTypeId}
            disabled={step === 'generating'}
            style={{ width: '100%', marginTop: 4 }}
            showSearch
            optionFilterProp="label"
            options={nodeTypes.map((nt) => ({
              label: `${nt.label} (${nt.category})`,
              value: String(nt.id),
            }))}
          />
        </div>

        {/* Prompt Input — visible once type is selected */}
        {selectedNodeTypeId && (
          <div>
            <Text strong>Describe your node instance</Text>
            <TextArea
              rows={4}
              placeholder={promptConfig.placeholder}
              value={prompt}
              onChange={(e) => setPrompt(e.target.value)}
              disabled={step === 'generating' || step === 'done'}
              style={{ marginTop: 4 }}
            />
          </div>
        )}

        {/* Generating state */}
        {step === 'generating' && (
          <>
            <Alert
              type="info"
              icon={<Spin indicator={<LoadingOutlined />} size="small" />}
              showIcon
              message="Waiting for Agent..."
              description="Continue your conversation with the Agent in the chat panel. Once it outputs valid JSON, it will be captured automatically. Or paste JSON below manually."
            />
            <div>
              <Text strong>JSON Result</Text>
              <Text type="secondary" style={{ marginLeft: 8, fontSize: 12 }}>
                Auto-filled by Agent or paste manually
              </Text>
              <TextArea
                rows={6}
                placeholder={
                  '{"name": "...", "description": "...", "config": {...}}'
                }
                value={resultInput}
                onChange={(e) => setResultInput(e.target.value)}
                style={{ marginTop: 4, fontFamily: 'monospace', fontSize: 12 }}
              />
            </div>
          </>
        )}

        {/* Done state */}
        {step === 'done' && generatedResult && (
          <>
            <Alert
              type="success"
              icon={<CheckCircleOutlined />}
              showIcon
              message="Node instance config generated!"
              description={`Name: ${generatedResult.name}. Config has ${Object.keys(generatedResult.config).length} fields.`}
            />
            <div>
              <Text strong>JSON Result</Text>
              <TextArea
                rows={6}
                value={resultInput}
                onChange={(e) => setResultInput(e.target.value)}
                style={{ marginTop: 4, fontFamily: 'monospace', fontSize: 12 }}
              />
            </div>
          </>
        )}

        {/* Agent error */}
        {agentError && (
          <Alert
            type="error"
            message="Generation failed"
            description={agentError}
            showIcon
          />
        )}

        {/* Action buttons */}
        <div style={{ textAlign: 'right' }}>
          <Space>
            <Button onClick={handleClose}>Cancel</Button>
            {step === 'selectType' && (
              <Button
                type="primary"
                disabled={!selectedNodeTypeId || !prompt.trim()}
                loading={agentLoading}
                onClick={handleGenerate}
              >
                Generate
              </Button>
            )}
            {step === 'generating' && (
              <Button
                type="primary"
                disabled={!resultInput.trim()}
                onClick={handleApplyManualJson}
              >
                Apply JSON
              </Button>
            )}
            {step === 'done' && (
              <>
                <Button
                  onClick={() => {
                    setStep('selectType');
                    setGeneratedResult(null);
                    setResultInput('');
                  }}
                >
                  Re-generate
                </Button>
                <Button
                  type="primary"
                  onClick={() => {
                    const parsed = tryParseNodeInstanceOutput(resultInput);
                    if (parsed) {
                      setGeneratedResult(parsed);
                      handleConfirm();
                    } else {
                      message.error('Invalid JSON format');
                    }
                  }}
                >
                  Confirm &amp; Create
                </Button>
              </>
            )}
          </Space>
        </div>
      </Space>
    </Modal>
  );
}
