import { useEffect, useState, type KeyboardEvent as ReactKeyboardEvent } from "react";

import { type ProjectDialogue } from "../dialogues/project-dialogues";

interface NpcDialoguesPanelProps {
  dialogues: ProjectDialogue[];
  defaultDialogueId: string | null;
  selectedDialogueId: string | null;
  onSelectDialogue(dialogueId: string | null): void;
  onSetDefaultDialogueId(dialogueId: string | null): void;
  onAddDialogue(): void;
  onDeleteDialogue(dialogueId: string): void;
  onSetDialogueTitle(dialogueId: string, title: string): void;
  onAddDialogueLine(dialogueId: string): void;
  onDeleteDialogueLine(dialogueId: string, lineId: string): void;
  onSetDialogueLineText(dialogueId: string, lineId: string, text: string): void;
}

function commitOnEnter(
  event: ReactKeyboardEvent<HTMLInputElement>,
  commit: () => void
) {
  if (event.key !== "Enter") {
    return;
  }

  event.currentTarget.blur();
  commit();
}

export function NpcDialoguesPanel({
  dialogues,
  defaultDialogueId,
  selectedDialogueId,
  onSelectDialogue,
  onSetDefaultDialogueId,
  onAddDialogue,
  onDeleteDialogue,
  onSetDialogueTitle,
  onAddDialogueLine,
  onDeleteDialogueLine,
  onSetDialogueLineText
}: NpcDialoguesPanelProps) {
  const selectedDialogue =
    selectedDialogueId === null
      ? null
      : dialogues.find((dialogue) => dialogue.id === selectedDialogueId) ?? null;
  const resolvedDefaultDialogueId =
    defaultDialogueId !== null &&
    dialogues.some((dialogue) => dialogue.id === defaultDialogueId)
      ? defaultDialogueId
      : null;
  const defaultDialogue =
    resolvedDefaultDialogueId === null
      ? null
      : dialogues.find((dialogue) => dialogue.id === resolvedDefaultDialogueId) ?? null;
  const [titleDraft, setTitleDraft] = useState(selectedDialogue?.title ?? "");
  const [lineDrafts, setLineDrafts] = useState<Record<string, { text: string }>>(
    {}
  );

  useEffect(() => {
    setTitleDraft(selectedDialogue?.title ?? "");
    setLineDrafts(
      selectedDialogue === null
        ? {}
        : Object.fromEntries(
            selectedDialogue.lines.map((line) => [
              line.id,
              {
                text: line.text
              }
            ])
          )
    );
  }, [selectedDialogueId, selectedDialogue]);

  const commitTitle = () => {
    if (selectedDialogue === null) {
      return;
    }

    onSetDialogueTitle(selectedDialogue.id, titleDraft);
  };

  const getLineDraft = (dialogue: ProjectDialogue, lineId: string) =>
    lineDrafts[lineId] ??
    (() => {
      const line = dialogue.lines.find((candidate) => candidate.id === lineId);
      return {
        text: line?.text ?? ""
      };
    })();

  return (
    <div className="form-section">
      <div className="stat-card">
        <div className="value">
          {defaultDialogue?.title ??
            (dialogues.length === 0 ? "No Dialogues" : "No Default Dialogue")}
        </div>
        <div className="material-summary">
          {dialogues.length === 0
            ? "Author one or more dialogues for this NPC. NPC sequence links can later make this NPC talk."
            : defaultDialogue === null
              ? "Pick a default dialogue for NPC talk effects that do not target a specific dialogue."
              : `${defaultDialogue.lines.length} line${defaultDialogue.lines.length === 1 ? "" : "s"} in the default NPC dialogue.`}
        </div>
      </div>

      <label className="form-field">
        <span className="label">Default Dialogue</span>
        <select
          data-testid="npc-default-dialogue"
          className="select-input"
          value={resolvedDefaultDialogueId ?? ""}
          onChange={(event) =>
            onSetDefaultDialogueId(
              event.currentTarget.value.trim().length === 0
                ? null
                : event.currentTarget.value
            )
          }
        >
          <option value="">— none —</option>
          {dialogues.map((dialogue) => (
            <option key={dialogue.id} value={dialogue.id}>
              {dialogue.title}
            </option>
          ))}
        </select>
      </label>

      <div className="label">Dialogues</div>
      {dialogues.length === 0 ? (
        <div className="outliner-empty">No NPC dialogues authored yet.</div>
      ) : (
        <div className="outliner-list">
          {dialogues.map((dialogue) => (
            <div
              key={dialogue.id}
              className={`outliner-item outliner-item--compact ${
                selectedDialogue?.id === dialogue.id
                  ? "outliner-item--selected"
                  : ""
              }`.trim()}
            >
              <div className="outliner-item__row">
                <button
                  className="outliner-item__select"
                  type="button"
                  onClick={() => onSelectDialogue(dialogue.id)}
                >
                  <span className="outliner-item__title">{dialogue.title}</span>
                  <span className="outliner-item__meta">
                    {dialogue.lines.length} line
                    {dialogue.lines.length === 1 ? "" : "s"}
                  </span>
                </button>
                <button
                  className="outliner-item__delete"
                  type="button"
                  aria-label={`Delete ${dialogue.title}`}
                  onClick={() => onDeleteDialogue(dialogue.id)}
                >
                  x
                </button>
              </div>
            </div>
          ))}
        </div>
      )}

      <div className="inline-actions">
        <button className="toolbar__button" type="button" onClick={onAddDialogue}>
          Add Dialogue
        </button>
      </div>

      {selectedDialogue === null ? (
        <div className="outliner-empty">
          Select a dialogue to edit its title and lines.
        </div>
      ) : (
        <div className="form-section">
          <label className="form-field">
            <span className="label">Title</span>
            <input
              className="text-input"
              type="text"
              value={titleDraft}
              onChange={(event) => {
                const nextValue = event.currentTarget.value;
                setTitleDraft(nextValue);
              }}
              onBlur={commitTitle}
              onKeyDown={(event) => commitOnEnter(event, commitTitle)}
            />
          </label>

          <div className="label">Lines</div>
          <div className="outliner-list">
            {selectedDialogue.lines.map((line, index) => {
              const draft = getLineDraft(selectedDialogue, line.id);

              return (
                <div key={line.id} className="outliner-item">
                  <div className="outliner-item__row">
                    <div className="outliner-item__meta">{`Line ${index + 1}`}</div>
                    <button
                      className="outliner-item__delete"
                      type="button"
                      aria-label={`Delete line ${index + 1}`}
                      onClick={() => onDeleteDialogueLine(selectedDialogue.id, line.id)}
                    >
                      x
                    </button>
                  </div>
                  <label className="form-field">
                    <span className="label">Text</span>
                    <textarea
                      className="text-input"
                      rows={3}
                      value={draft.text}
                      onChange={(event) => {
                        const nextText = event.currentTarget.value;

                        setLineDrafts((current) => ({
                          ...current,
                          [line.id]: {
                            ...draft,
                            text: nextText
                          }
                        }));
                      }}
                      onBlur={() =>
                        onSetDialogueLineText(
                          selectedDialogue.id,
                          line.id,
                          draft.text
                        )
                      }
                    />
                  </label>
                </div>
              );
            })}
          </div>

          <div className="inline-actions">
            <button
              className="toolbar__button"
              type="button"
              onClick={() => onAddDialogueLine(selectedDialogue.id)}
            >
              Add Line
            </button>
          </div>
        </div>
      )}
    </div>
  );
}
