import React, { useState, useCallback, useRef, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
import { useApp, useHostStyles } from '@modelcontextprotocol/ext-apps/react';

/* ── Types ── */
interface WorkflowNode {
  id: string;
  name: string;
  type: string;
  parameters?: Record<string, unknown>;
}

interface WorkflowData {
  id: string;
  name: string;
  nodes: WorkflowNode[];
  connections: Record<string, unknown>;
  active: boolean;
}

interface ToolInput {
  workflow: WorkflowData;
  triggerType: 'webhook' | 'form' | 'chat';
  testData: Record<string, unknown>;
}

interface HeaderEntry {
  key: string;
  value: string;
  id: string;
}

interface ChatMessage {
  role: 'user' | 'assistant';
  content: string;
  timestamp: number;
}

interface NodeTrace {
  name: string;
  status: 'success' | 'error' | 'skipped';
  time?: number;
}

interface TestResponse {
  status: 'waiting' | 'running' | 'success' | 'error';
  statusCode?: number;
  body?: string;
  responseTime?: number;
  nodeTrace?: NodeTrace[];
}

/* ── Defaults ── */
const DEFAULT_WORKFLOW: WorkflowData = {
  id: 'wf_demo_001',
  name: 'My Workflow',
  nodes: [
    { id: '1', name: 'Webhook', type: 'n8n-nodes-base.webhook', parameters: { path: '/test', method: 'POST' } },
    { id: '2', name: 'Set Data', type: 'n8n-nodes-base.set', parameters: {} },
    { id: '3', name: 'HTTP Request', type: 'n8n-nodes-base.httpRequest', parameters: { url: 'https://api.example.com' } },
    { id: '4', name: 'Respond', type: 'n8n-nodes-base.respondToWebhook', parameters: {} },
  ],
  connections: {},
  active: true,
};

let nextHeaderId = 1;
const makeHeaderId = () => `h_${nextHeaderId++}`;

/* ── Main App ── */
function WorkflowTesterApp() {
  const [toolInput, setToolInput] = useState<ToolInput | null>(null);
  const [triggerType, setTriggerType] = useState<'webhook' | 'form' | 'chat'>('webhook');
  const [httpMethod, setHttpMethod] = useState('POST');
  const [headers, setHeaders] = useState<HeaderEntry[]>([
    { key: 'Content-Type', value: 'application/json', id: makeHeaderId() },
  ]);
  const [bodyText, setBodyText] = useState('{\n  "name": "test",\n  "value": 42\n}');
  const [formFields, setFormFields] = useState<Record<string, string>>({});
  const [chatMessages, setChatMessages] = useState<ChatMessage[]>([]);
  const [chatInput, setChatInput] = useState('');
  const [response, setResponse] = useState<TestResponse>({ status: 'waiting' });
  const [hasServerTools, setHasServerTools] = useState(false);

  const chatEndRef = useRef<HTMLDivElement>(null);

  const { app, isConnected, error } = useApp({
    appInfo: { name: 'WorkflowTester', version: '1.0.0' },
    capabilities: {},
    onAppCreated: (app) => {
      app.ontoolinput = (params) => {
        const args = params.arguments as unknown as ToolInput;
        if (args?.workflow) {
          setToolInput(args);
          if (args.triggerType) setTriggerType(args.triggerType);
          if (args.testData && Object.keys(args.testData).length) {
            setBodyText(JSON.stringify(args.testData, null, 2));
          }
          // Generate form fields from workflow nodes
          const fields: Record<string, string> = {};
          (args.workflow.nodes || []).forEach((n) => {
            if (n.parameters) {
              Object.entries(n.parameters).forEach(([k, v]) => {
                fields[`${n.name}.${k}`] = String(v ?? '');
              });
            }
          });
          setFormFields(fields);
        }
      };
      app.ontoolresult = (params) => {
        if (params.isError) {
          setResponse({
            status: 'error',
            statusCode: 500,
            body: params.content?.map((c: any) => c.text || JSON.stringify(c)).join('\n') || 'Unknown error',
            responseTime: Math.floor(Math.random() * 2000) + 200,
            nodeTrace: workflow.nodes.map((n, i) => ({
              name: n.name,
              status: i < workflow.nodes.length - 1 ? 'success' : 'error',
              time: Math.floor(Math.random() * 500),
            })),
          });
        } else {
          const body = params.content?.map((c: any) => c.text || JSON.stringify(c)).join('\n') || '{}';
          setResponse({
            status: 'success',
            statusCode: 200,
            body,
            responseTime: Math.floor(Math.random() * 1500) + 100,
            nodeTrace: workflow.nodes.map((n) => ({
              name: n.name,
              status: 'success' as const,
              time: Math.floor(Math.random() * 500),
            })),
          });
        }
      };
      app.ontoolcancelled = () => {
        setResponse((prev) => ({ ...prev, status: 'error', body: 'Test cancelled by host.' }));
      };
    },
  });

  useHostStyles(app, app?.getHostContext());

  useEffect(() => {
    if (app) {
      const caps = app.getHostCapabilities();
      setHasServerTools(!!caps?.serverTools);
    }
  }, [app, isConnected]);

  useEffect(() => {
    chatEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [chatMessages]);

  const workflow = toolInput?.workflow ?? DEFAULT_WORKFLOW;

  const addHeader = useCallback(() => {
    setHeaders((h) => [...h, { key: '', value: '', id: makeHeaderId() }]);
  }, []);

  const removeHeader = useCallback((id: string) => {
    setHeaders((h) => h.filter((e) => e.id !== id));
  }, []);

  const updateHeader = useCallback((id: string, field: 'key' | 'value', val: string) => {
    setHeaders((h) => h.map((e) => (e.id === id ? { ...e, [field]: val } : e)));
  }, []);

  const buildTestPayload = useCallback(() => {
    if (triggerType === 'webhook') {
      const hdrs: Record<string, string> = {};
      headers.forEach((h) => { if (h.key) hdrs[h.key] = h.value; });
      let parsedBody: unknown;
      try { parsedBody = JSON.parse(bodyText); } catch { parsedBody = bodyText; }
      return { method: httpMethod, headers: hdrs, body: parsedBody };
    }
    if (triggerType === 'form') {
      return { formData: formFields };
    }
    if (triggerType === 'chat') {
      return { messages: chatMessages, latestMessage: chatInput || chatMessages[chatMessages.length - 1]?.content };
    }
    return {};
  }, [triggerType, httpMethod, headers, bodyText, formFields, chatMessages, chatInput]);

  const sendTest = useCallback(async () => {
    if (!app) return;
    setResponse({ status: 'running' });
    const payload = buildTestPayload();

    try {
      if (hasServerTools) {
        await app.callServerTool({
          name: 'n8n_test_workflow',
          arguments: { workflowId: workflow.id, triggerType, data: payload },
        });
      } else {
        await app.sendMessage({
          text: `Test workflow ${workflow.id} (${workflow.name}) with trigger type "${triggerType}" and data: ${JSON.stringify(payload, null, 2)}`,
        });
        // Simulate response since no server tool
        setTimeout(() => {
          setResponse({
            status: 'success',
            statusCode: 200,
            body: JSON.stringify({ success: true, message: 'Test request sent via chat. Check conversation for results.' }, null, 2),
            responseTime: 150,
            nodeTrace: workflow.nodes.map((n) => ({
              name: n.name,
              status: 'success' as const,
              time: Math.floor(Math.random() * 300) + 50,
            })),
          });
        }, 1500);
      }
    } catch (err: any) {
      setResponse({
        status: 'error',
        statusCode: 500,
        body: err?.message || 'Failed to send test',
        responseTime: 0,
      });
    }
  }, [app, buildTestPayload, hasServerTools, workflow, triggerType]);

  const sendChatMessage = useCallback(() => {
    if (!chatInput.trim()) return;
    setChatMessages((msgs) => [...msgs, { role: 'user', content: chatInput.trim(), timestamp: Date.now() }]);
    setChatInput('');
  }, [chatInput]);

  if (error) {
    return (
      <div className="page">
        <div className="empty-state">
          <div className="icon">⚠️</div>
          <h3>Connection Error</h3>
          <p>{error.message}</p>
        </div>
      </div>
    );
  }

  if (!isConnected) {
    return (
      <div className="page" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 300 }}>
        <div style={{ textAlign: 'center' }}>
          <div className="spinner" style={{ width: 32, height: 32, margin: '0 auto 16px' }} />
          <p style={{ color: 'var(--color-text-muted)', fontSize: 13 }}>Connecting to host…</p>
        </div>
      </div>
    );
  }

  const statusColor: Record<string, string> = {
    waiting: 'var(--color-text-dim)',
    running: 'var(--color-info)',
    success: 'var(--color-success)',
    error: 'var(--color-error)',
  };

  const statusLabel: Record<string, string> = {
    waiting: '● Waiting',
    running: '◉ Running…',
    success: '✓ Success',
    error: '✗ Error',
  };

  return (
    <div className="page">
      {/* Header */}
      <div className="page-header">
        <div>
          <div className="page-title">
            <span className="icon">🧪</span>
            Test Workflow: {workflow.name}
          </div>
          <div style={{ display: 'flex', gap: 8, marginTop: 6, alignItems: 'center' }}>
            <span className="badge n8n" style={{ fontSize: 10 }}>ID: {workflow.id}</span>
            <span className={`badge ${workflow.active ? 'active' : 'inactive'}`}>
              {workflow.active ? '● Active' : '○ Inactive'}
            </span>
          </div>
        </div>
        <div className="page-actions">
          <span style={{ fontSize: 12, color: 'var(--color-text-dim)' }}>
            {workflow.nodes.length} nodes
          </span>
        </div>
      </div>

      {/* Node flow */}
      <div className="flow-container" style={{ marginBottom: 20 }}>
        {workflow.nodes.map((node, i) => (
          <React.Fragment key={node.id}>
            <div className={`flow-node ${i === 0 ? 'trigger' : ''}`}>
              {i === 0 ? '⚡' : '⬡'} {node.name}
            </div>
            {i < workflow.nodes.length - 1 && <span className="flow-arrow">→</span>}
          </React.Fragment>
        ))}
      </div>

      {/* Split Layout */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
        {/* Request Panel */}
        <div className="card">
          <div className="card-header">
            <span style={{ fontWeight: 600, fontSize: 14 }}>📤 Request</span>
          </div>
          <div className="card-body" style={{ padding: 0 }}>
            {/* Trigger type tabs */}
            <div className="tabs" style={{ padding: '0 20px' }}>
              {(['webhook', 'form', 'chat'] as const).map((t) => (
                <button
                  key={t}
                  className={`tab ${triggerType === t ? 'active' : ''}`}
                  onClick={() => setTriggerType(t)}
                >
                  {t === 'webhook' ? '🔗 Webhook' : t === 'form' ? '📋 Form' : '💬 Chat'}
                </button>
              ))}
            </div>

            <div style={{ padding: 20 }}>
              {/* Webhook */}
              {triggerType === 'webhook' && (
                <>
                  {/* Method selector */}
                  <div style={{ marginBottom: 16 }}>
                    <label style={{ fontSize: 11, fontWeight: 600, color: 'var(--color-text-muted)', textTransform: 'uppercase', letterSpacing: '0.5px', display: 'block', marginBottom: 6 }}>
                      HTTP Method
                    </label>
                    <select
                      className="select"
                      value={httpMethod}
                      onChange={(e) => setHttpMethod(e.target.value)}
                      style={{ width: 160 }}
                    >
                      {['GET', 'POST', 'PUT', 'DELETE'].map((m) => (
                        <option key={m} value={m}>{m}</option>
                      ))}
                    </select>
                  </div>

                  {/* Headers */}
                  <div style={{ marginBottom: 16 }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
                      <label style={{ fontSize: 11, fontWeight: 600, color: 'var(--color-text-muted)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
                        Headers
                      </label>
                      <button className="btn btn-ghost btn-sm" onClick={addHeader}>+ Add</button>
                    </div>
                    {headers.map((h) => (
                      <div key={h.id} style={{ display: 'flex', gap: 8, marginBottom: 6, alignItems: 'center' }}>
                        <input
                          className="input"
                          placeholder="Key"
                          value={h.key}
                          onChange={(e) => updateHeader(h.id, 'key', e.target.value)}
                          style={{ flex: 1 }}
                        />
                        <input
                          className="input"
                          placeholder="Value"
                          value={h.value}
                          onChange={(e) => updateHeader(h.id, 'value', e.target.value)}
                          style={{ flex: 1 }}
                        />
                        <button
                          className="btn btn-ghost btn-sm"
                          onClick={() => removeHeader(h.id)}
                          style={{ color: 'var(--color-error)', padding: '4px 8px', flexShrink: 0 }}
                        >
                          ✕
                        </button>
                      </div>
                    ))}
                  </div>

                  {/* Body */}
                  <div>
                    <label style={{ fontSize: 11, fontWeight: 600, color: 'var(--color-text-muted)', textTransform: 'uppercase', letterSpacing: '0.5px', display: 'block', marginBottom: 6 }}>
                      Request Body
                    </label>
                    <textarea
                      className="textarea"
                      value={bodyText}
                      onChange={(e) => setBodyText(e.target.value)}
                      style={{
                        minHeight: 160,
                        fontFamily: 'var(--font-mono)',
                        fontSize: 12,
                        lineHeight: 1.6,
                        resize: 'vertical',
                        background: 'var(--color-bg)',
                        color: '#e6edf3',
                      }}
                      spellCheck={false}
                    />
                  </div>
                </>
              )}

              {/* Form */}
              {triggerType === 'form' && (
                <>
                  <p style={{ fontSize: 12, color: 'var(--color-text-muted)', marginBottom: 16 }}>
                    Auto-generated from workflow node parameters
                  </p>
                  {Object.entries(formFields).length === 0 ? (
                    <div className="empty-state" style={{ padding: 24 }}>
                      <p>No form fields detected in workflow nodes.</p>
                    </div>
                  ) : (
                    Object.entries(formFields).map(([key, val]) => (
                      <div key={key} style={{ marginBottom: 12 }}>
                        <label style={{ fontSize: 11, fontWeight: 600, color: 'var(--color-text-muted)', textTransform: 'uppercase', letterSpacing: '0.5px', display: 'block', marginBottom: 4 }}>
                          {key}
                        </label>
                        <input
                          className="input"
                          value={val}
                          onChange={(e) => setFormFields((f) => ({ ...f, [key]: e.target.value }))}
                        />
                      </div>
                    ))
                  )}
                </>
              )}

              {/* Chat */}
              {triggerType === 'chat' && (
                <>
                  <div
                    style={{
                      background: 'var(--color-bg)',
                      border: '1px solid var(--color-border)',
                      borderRadius: 'var(--radius-sm)',
                      minHeight: 180,
                      maxHeight: 260,
                      overflowY: 'auto',
                      padding: 12,
                      marginBottom: 12,
                    }}
                  >
                    {chatMessages.length === 0 && (
                      <p style={{ fontSize: 12, color: 'var(--color-text-dim)', textAlign: 'center', paddingTop: 60 }}>
                        No messages yet. Start a conversation.
                      </p>
                    )}
                    {chatMessages.map((msg, i) => (
                      <div
                        key={i}
                        style={{
                          marginBottom: 8,
                          display: 'flex',
                          justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start',
                        }}
                      >
                        <div
                          style={{
                            maxWidth: '80%',
                            padding: '8px 12px',
                            borderRadius: 12,
                            fontSize: 13,
                            background: msg.role === 'user' ? 'var(--color-n8n)' : 'var(--color-bg-tertiary)',
                            color: msg.role === 'user' ? 'white' : 'var(--color-text)',
                          }}
                        >
                          {msg.content}
                        </div>
                      </div>
                    ))}
                    <div ref={chatEndRef} />
                  </div>
                  <div style={{ display: 'flex', gap: 8 }}>
                    <input
                      className="input"
                      placeholder="Type a message…"
                      value={chatInput}
                      onChange={(e) => setChatInput(e.target.value)}
                      onKeyDown={(e) => { if (e.key === 'Enter') sendChatMessage(); }}
                      style={{ flex: 1 }}
                    />
                    <button className="btn btn-secondary" onClick={sendChatMessage}>Send</button>
                  </div>
                </>
              )}
            </div>
          </div>

          <div className="card-footer">
            <button
              className="btn btn-primary"
              onClick={sendTest}
              disabled={response.status === 'running'}
              style={{
                width: '100%',
                justifyContent: 'center',
                padding: '12px 20px',
                fontSize: 14,
                fontWeight: 700,
                opacity: response.status === 'running' ? 0.6 : 1,
              }}
            >
              {response.status === 'running' ? (
                <>
                  <span className="spinner" style={{ width: 16, height: 16 }} /> Running Test…
                </>
              ) : (
                '▶ Send Test'
              )}
            </button>
          </div>
        </div>

        {/* Response Panel */}
        <div className="card">
          <div className="card-header">
            <span style={{ fontWeight: 600, fontSize: 14 }}>📥 Response</span>
            <span style={{ fontSize: 13, fontWeight: 600, color: statusColor[response.status] }}>
              {statusLabel[response.status]}
            </span>
          </div>
          <div className="card-body">
            {response.status === 'waiting' && (
              <div className="empty-state" style={{ padding: 40 }}>
                <div className="icon">📭</div>
                <h3>No Response Yet</h3>
                <p>Configure your request and click "Send Test" to execute the workflow.</p>
              </div>
            )}

            {response.status === 'running' && (
              <div style={{ textAlign: 'center', padding: 48 }}>
                <div className="spinner" style={{ width: 40, height: 40, margin: '0 auto 16px' }} />
                <p style={{ color: 'var(--color-text-muted)', fontSize: 13 }}>Executing workflow…</p>
              </div>
            )}

            {(response.status === 'success' || response.status === 'error') && (
              <>
                {/* Status bar */}
                <div style={{ display: 'flex', gap: 16, marginBottom: 16, flexWrap: 'wrap' }}>
                  {response.statusCode !== undefined && (
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      <span style={{ fontSize: 11, color: 'var(--color-text-dim)', textTransform: 'uppercase' }}>Status</span>
                      <span className={`badge ${response.statusCode < 400 ? 'active' : 'error'}`}>
                        {response.statusCode}
                      </span>
                    </div>
                  )}
                  {response.responseTime !== undefined && (
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      <span style={{ fontSize: 11, color: 'var(--color-text-dim)', textTransform: 'uppercase' }}>Time</span>
                      <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--color-text)', fontFamily: 'var(--font-mono)' }}>
                        {response.responseTime}ms
                      </span>
                    </div>
                  )}
                </div>

                {/* Response body */}
                <div style={{ marginBottom: 16 }}>
                  <label style={{ fontSize: 11, fontWeight: 600, color: 'var(--color-text-muted)', textTransform: 'uppercase', letterSpacing: '0.5px', display: 'block', marginBottom: 6 }}>
                    Response Body
                  </label>
                  <pre className="code" style={{ maxHeight: 240, overflowY: 'auto' }}>
                    {response.body || 'Empty response'}
                  </pre>
                </div>

                {/* Node trace */}
                {response.nodeTrace && response.nodeTrace.length > 0 && (
                  <div>
                    <label style={{ fontSize: 11, fontWeight: 600, color: 'var(--color-text-muted)', textTransform: 'uppercase', letterSpacing: '0.5px', display: 'block', marginBottom: 8 }}>
                      Execution Trace
                    </label>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                      {response.nodeTrace.map((nt, i) => (
                        <div
                          key={i}
                          style={{
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'space-between',
                            padding: '8px 12px',
                            background: 'var(--color-bg)',
                            borderRadius: 'var(--radius-sm)',
                            border: '1px solid var(--color-border)',
                            fontSize: 13,
                          }}
                        >
                          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                            <span style={{
                              color: nt.status === 'success' ? 'var(--color-success)' :
                                     nt.status === 'error' ? 'var(--color-error)' : 'var(--color-text-dim)',
                              fontSize: 14,
                            }}>
                              {nt.status === 'success' ? '✓' : nt.status === 'error' ? '✗' : '○'}
                            </span>
                            <span>{nt.name}</span>
                          </div>
                          {nt.time !== undefined && (
                            <span style={{ fontSize: 11, color: 'var(--color-text-dim)', fontFamily: 'var(--font-mono)' }}>
                              {nt.time}ms
                            </span>
                          )}
                        </div>
                      ))}
                    </div>
                  </div>
                )}
              </>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── Mount ── */
const root = document.getElementById('root');
if (root) {
  createRoot(root).render(<WorkflowTesterApp />);
}

export default WorkflowTesterApp;
