import NpcDialogueSimulationPanel from "./NpcDialogueSimulationPanel";
import type { NpcDialogueEditorContext } from "./editorContexts";

type NpcDialogueEditorPanelProps = {
  ctx: NpcDialogueEditorContext;
};

export default function NpcDialogueEditorPanel({ ctx }: NpcDialogueEditorPanelProps) {
  const {
    activeType,
    selectedRecord,
    activeEditTab,
    addDialogueNode,
    deleteDialogueNode,
    selectedDialogueNode,
    moveDialogueNode,
    selectedDialogueNodeIndex,
    dialogueNodes,
    setSelectedDialogueNodeIndex,
    selectedDialogueFieldEntries,
    toFieldLabel,
    handleDialogueNodeFieldChange,
    patchFlowSteps,
    createFlowStep,
    selectedFlowSteps,
    isStepCollapsed,
    dropTargetStepId,
    draggingStepId,
    setDraggingStepId,
    setDropTargetStepId,
    moveFlowStepById,
    setStepCollapsed,
    FLOW_KIND_LABELS,
    getFlowStepSummary,
    moveFlowStepByDirection,
    conditionTypeOptions,
    getDefaultConditionValue,
    renderConditionValueField,
    dialogueNodeIds,
    DIALOGUE_REACTION_TYPES,
    simSandbox,
    simCurrentNodeId,
    simText,
    simChoices,
    simFallbackNextId,
    simEnded,
    startSimulation,
    updateSandbox,
    chooseSimChoice,
    continueSimulation,
    isLoading,
    isSaving,
  } = ctx;

  if (!(activeType === "dialogues" && selectedRecord && activeEditTab === "Dialogue")) {
    return null;
  }

  return (
    <div className="dialogue-editor">
      <div className="dialogue-editor-head">
        <h3>Dialogue Nodes</h3>
        <div className="dialogue-actions">
          <button type="button" className="success" onClick={addDialogueNode} disabled={isLoading || isSaving}>Add Node</button>
          <button type="button" className="danger" onClick={deleteDialogueNode} disabled={!selectedDialogueNode || isLoading || isSaving}>Delete Node</button>
          <button type="button" onClick={() => moveDialogueNode(-1)} disabled={!selectedDialogueNode || selectedDialogueNodeIndex <= 0 || isLoading || isSaving}>Move Up</button>
          <button type="button" onClick={() => moveDialogueNode(1)} disabled={!selectedDialogueNode || selectedDialogueNodeIndex >= dialogueNodes.length - 1 || isLoading || isSaving}>Move Down</button>
        </div>
      </div>

      <div className="dialogue-layout">
        <div className="dialogue-node-list">
          {dialogueNodes.length === 0 ? <p className="muted">No dialogue nodes yet.</p> : null}
          {dialogueNodes.map((node, index) => {
            const nodeId = String(node.id || `node-${index + 1}`);
            const preview = String(node.description || node.text || "").trim();
            return (
              <button
                key={`${nodeId}-${index}`}
                type="button"
                className={`record-row ${index === selectedDialogueNodeIndex ? "is-active" : ""}`}
                onClick={() => setSelectedDialogueNodeIndex(index)}
              >
                {nodeId}{preview ? ` - ${preview.slice(0, 48)}` : ""}
              </button>
            );
          })}
        </div>

        <div className="dialogue-node-fields">
          {!selectedDialogueNode ? <p className="muted">Select a node to edit.</p> : null}
          {selectedDialogueNode ? (
            <>
              <div className="fields-grid">
                {selectedDialogueFieldEntries.map(([key, value]) => {
                  if (["choices", "conditions", "reactions"].includes(key)) {
                    return null;
                  }

                  if (Array.isArray(value) || (value !== null && typeof value === "object")) {
                    const itemCount = Array.isArray(value) ? value.length : Object.keys(value as object).length;
                    return (
                      <div key={`dialogue-${key}`} className="field-row">
                        <label>{toFieldLabel(key)}</label>
                        <p className="muted">Complex value ({itemCount}). Edit in Raw JSON below.</p>
                      </div>
                    );
                  }

                  if (typeof value === "boolean") {
                    return (
                      <div key={`dialogue-${key}`} className="field-row">
                        <label htmlFor={`dialogue-field-${key}`}>{toFieldLabel(key)}</label>
                        <select id={`dialogue-field-${key}`} value={String(value)} onChange={(event) => handleDialogueNodeFieldChange(key, event.target.value)}>
                          <option value="true">true</option>
                          <option value="false">false</option>
                        </select>
                      </div>
                    );
                  }

                  return (
                    <div key={`dialogue-${key}`} className="field-row">
                      <label htmlFor={`dialogue-field-${key}`}>{toFieldLabel(key)}</label>
                      <input
                        id={`dialogue-field-${key}`}
                        type={typeof value === "number" ? "number" : "text"}
                        value={value === null ? "" : String(value)}
                        onChange={(event) => handleDialogueNodeFieldChange(key, event.target.value)}
                      />
                    </div>
                  );
                })}
              </div>

              <div className="mini-editor">
                <div className="mini-editor-head">
                  <h4>Flow Timeline</h4>
                  <div className="flow-add-buttons">
                    <button type="button" onClick={() => patchFlowSteps((steps) => [...steps, createFlowStep("condition")])}>+ Condition</button>
                    <button type="button" onClick={() => patchFlowSteps((steps) => [...steps, createFlowStep("action")])}>+ Action</button>
                    <button type="button" onClick={() => patchFlowSteps((steps) => [...steps, createFlowStep("jump")])}>+ Jump</button>
                    <button type="button" onClick={() => patchFlowSteps((steps) => [...steps, createFlowStep("choice")])}>+ Choice</button>
                    <button type="button" onClick={() => patchFlowSteps((steps) => [...steps, createFlowStep("text")])}>+ Text Screen</button>
                    <button type="button" onClick={() => patchFlowSteps((steps) => [...steps, createFlowStep("end")])}>+ End</button>
                  </div>
                </div>

                {selectedFlowSteps.length === 0 ? <p className="muted">No flow steps yet. Add a step above.</p> : null}
                {selectedFlowSteps.map((step, index) => {
                  const stepConditionType = String(step.conditionType || "always");
                  const collapsed = isStepCollapsed(step.id);
                  const nextStep = selectedFlowSteps[index + 1];
                  return (
                    <div
                      key={step.id}
                      className={`flow-step ${collapsed ? "collapsed" : "expanded"} ${dropTargetStepId === step.id ? "drop-target" : ""}`}
                      draggable
                      onDragStart={() => setDraggingStepId(step.id)}
                      onDragOver={(event) => {
                        event.preventDefault();
                        setDropTargetStepId(step.id);
                      }}
                      onDrop={(event) => {
                        event.preventDefault();
                        moveFlowStepById(draggingStepId, step.id);
                        setDraggingStepId("");
                        setDropTargetStepId("");
                      }}
                      onDragEnd={() => {
                        setDraggingStepId("");
                        setDropTargetStepId("");
                      }}
                    >
                      <div
                        className="flow-step-head flow-step-toggle"
                        role="button"
                        tabIndex={0}
                        onClick={() => setStepCollapsed(step.id, !collapsed)}
                        onKeyDown={(event) => {
                          if (event.key === "Enter" || event.key === " ") {
                            event.preventDefault();
                            setStepCollapsed(step.id, !collapsed);
                          }
                        }}
                      >
                        <div>
                          <strong>{index + 1}. {FLOW_KIND_LABELS[step.kind]}</strong>
                          {collapsed ? <p className="flow-summary">{getFlowStepSummary(step)}</p> : null}
                        </div>
                        {collapsed && nextStep ? <p className="flow-next-preview">Next: ({index + 2}) {FLOW_KIND_LABELS[nextStep.kind]} - {getFlowStepSummary(nextStep).slice(0, 45)}</p> : null}

                        {!collapsed ? (
                          <div className="flow-step-actions flow-expanded-actions" onClick={(event) => event.stopPropagation()}>
                            <button
                              type="button"
                              onClick={() => moveFlowStepByDirection(step.id, -1)}
                              disabled={index === 0}
                              title="Move up"
                            >
                              -
                            </button>
                            <button
                              type="button"
                              onClick={() => moveFlowStepByDirection(step.id, 1)}
                              disabled={index >= selectedFlowSteps.length - 1}
                              title="Move down"
                            >
                              +
                            </button>
                            <button type="button" onClick={() => patchFlowSteps((steps) => steps.filter((_, idx) => idx !== index))}>Remove</button>
                          </div>
                        ) : null}
                      </div>

                      {!collapsed && step.kind === "text" ? (
                        <textarea
                          value={String(step.text || "")}
                          onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, text: event.target.value } : entry)))}
                          placeholder="Screen text"
                        />
                      ) : null}

                      {!collapsed && step.kind === "jump" ? (
                        <select
                          value={String(step.nextId || "")}
                          onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, nextId: event.target.value } : entry)))}
                        >
                          <option value="">Select node</option>
                          {dialogueNodeIds.map((id: string) => (
                            <option key={`flow-jump-${step.id}-${id}`} value={id}>{id}</option>
                          ))}
                        </select>
                      ) : null}

                      {!collapsed && step.kind === "action" ? (
                        <div className="flow-step-grid">
                          <select
                            value={String(step.reactionType || "none")}
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, reactionType: event.target.value } : entry)))}
                          >
                            {DIALOGUE_REACTION_TYPES.map((opt: string) => (
                              <option key={`flow-action-${step.id}-${opt}`} value={opt}>{opt}</option>
                            ))}
                          </select>
                          <input
                            value={String(step.reactionValue || "")}
                            placeholder="Action value"
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, reactionValue: event.target.value } : entry)))}
                          />
                        </div>
                      ) : null}

                      {!collapsed && step.kind === "condition" ? (
                        <div className="flow-step-grid">
                          <select
                            value={stepConditionType}
                            onChange={(event) => {
                              const nextType = event.target.value;
                              patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? {
                                ...entry,
                                conditionType: nextType,
                                conditionValue: getDefaultConditionValue(nextType),
                              } : entry)));
                            }}
                          >
                            {conditionTypeOptions.map((opt: string) => (
                              <option key={`flow-cond-type-${step.id}-${opt}`} value={opt}>{opt}</option>
                            ))}
                          </select>
                          {renderConditionValueField(stepConditionType, String(step.conditionValue || ""), (nextValue: string) => {
                            patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, conditionValue: nextValue } : entry)));
                          })}
                          <input
                            value={String(step.text || "")}
                            placeholder="Output text"
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, text: event.target.value } : entry)))}
                          />
                          <select
                            value={String(step.nextId || "")}
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, nextId: event.target.value } : entry)))}
                          >
                            <option value="">No jump</option>
                            {dialogueNodeIds.map((id: string) => (
                              <option key={`flow-cond-next-${step.id}-${id}`} value={id}>{id}</option>
                            ))}
                          </select>
                          <label className="inline-check">
                            <input
                              type="checkbox"
                              checked={Boolean(step.conditionNot)}
                              onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, conditionNot: event.target.checked } : entry)))}
                            />
                            not
                          </label>
                        </div>
                      ) : null}

                      {!collapsed && step.kind === "choice" ? (
                        <div className="flow-step-grid">
                          <input
                            value={String(step.text || "")}
                            placeholder="Choice text"
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, text: event.target.value } : entry)))}
                          />
                          <select
                            value={String(step.nextId || "")}
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, nextId: event.target.value } : entry)))}
                          >
                            <option value="">End</option>
                            {dialogueNodeIds.map((id: string) => (
                              <option key={`flow-choice-next-${step.id}-${id}`} value={id}>{id}</option>
                            ))}
                          </select>
                          <select
                            value={stepConditionType}
                            onChange={(event) => {
                              const nextType = event.target.value;
                              patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? {
                                ...entry,
                                conditionType: nextType,
                                conditionValue: getDefaultConditionValue(nextType),
                              } : entry)));
                            }}
                          >
                            {conditionTypeOptions.map((opt: string) => (
                              <option key={`flow-choice-cond-${step.id}-${opt}`} value={opt}>{opt}</option>
                            ))}
                          </select>
                          {renderConditionValueField(stepConditionType, String(step.conditionValue || ""), (nextValue: string) => {
                            patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, conditionValue: nextValue } : entry)));
                          })}
                          <label className="inline-check">
                            <input
                              type="checkbox"
                              checked={Boolean(step.conditionNot)}
                              onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, conditionNot: event.target.checked } : entry)))}
                            />
                            not
                          </label>
                          <select
                            value={String(step.reactionType || "none")}
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, reactionType: event.target.value } : entry)))}
                          >
                            {DIALOGUE_REACTION_TYPES.map((opt: string) => (
                              <option key={`flow-choice-react-${step.id}-${opt}`} value={opt}>{opt}</option>
                            ))}
                          </select>
                          <input
                            value={String(step.reactionValue || "")}
                            placeholder="Choice action value"
                            onChange={(event) => patchFlowSteps((steps) => steps.map((entry, idx) => (idx === index ? { ...entry, reactionValue: event.target.value } : entry)))}
                          />
                        </div>
                      ) : null}

                      {!collapsed && step.kind === "end" ? <p className="muted">Ends the conversation immediately when reached.</p> : null}
                    </div>
                  );
                })}
              </div>
            </>
          ) : null}
        </div>
      </div>

      <NpcDialogueSimulationPanel
        dialogueNodesLength={dialogueNodes.length}
        simSandbox={simSandbox}
        simCurrentNodeId={simCurrentNodeId}
        simText={simText}
        simChoices={simChoices}
        simFallbackNextId={simFallbackNextId}
        simEnded={simEnded}
        onStartSimulation={startSimulation}
        onUpdateSandbox={updateSandbox}
        onChooseSimChoice={chooseSimChoice}
        onContinueSimulation={continueSimulation}
      />
    </div>
  );
}
