import React, { useEffect, useId, useRef, useState } from "react";
import { __, sprintf } from "@wordpress/i18n";
import {
  SortableContext,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import {
  Plus,
  GripVertical,
  ChevronUp,
  ChevronDown,
  ChevronRight,
  Trash2,
  Copy,
  Workflow,
  X,
  Pencil,
} from "lucide-react";
import Modal from "@libs/modal";
import SortableRule from "./SortableRule";
import ConditionBuilder from "./ConditionBuilder";
import ScheduleFields from "./ScheduleFields";
import { getFlowSections, getSectionSummary } from "./flowSections";
import useStickyRuleFlow, { STACKED_LAYOUT_QUERY } from "./useStickyRuleFlow";
import "./flow-editor.scss";

const FlowArrow = () => (
  <svg
    className="arraysubs-rule-flow__arrow"
    width="28"
    height="34"
    viewBox="0 0 28 34"
    fill="none"
    aria-hidden="true"
  >
    <path
      d="M14 1v29M6 22l8 9 8-9"
      stroke="currentColor"
      strokeWidth="1.8"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  </svg>
);

const RuleFlowEditor = ({
  rules,
  ruleType,
  ruleLabel,
  conditionTypes,
  sidebarContent,
  renderTargetFields,
  renderActionFields,
  showSchedule,
  accessRule,
  reducedMotion,
  onAdd,
  onUpdate,
  onDelete,
  onDuplicate,
  onMoveUp,
  onMoveDown,
  onToggle,
}) => {
  const [selectedId, setSelectedId] = useState(null);
  const [openSection, setOpenSection] = useState(null);
  const flowId = useId();
  const workspaceRef = useRef(null);
  const canvasRef = useRef(null);
  const contentRef = useRef(null);
  const revealCanvas = useStickyRuleFlow({
    workspaceRef,
    trackRef: canvasRef,
    canvasRef: contentRef,
  });
  const selectRefs = useRef(new Map());
  const rule = rules.find((item) => item.id === selectedId);
  const sections = getFlowSections({
    ruleType,
    accessRule,
    hasTarget: !!renderTargetFields,
    hasAction: !!renderActionFields,
    showSchedule,
  });
  const section = sections.find((item) => item.id === openSection);
  const enabled = rule?.enabled !== false;

  // Discard, deletion, or a reload may remove the selected rule. UI state never
  // becomes part of the persisted object, including when a rule is reordered.
  useEffect(() => {
    if (selectedId && !rules.some((item) => item.id === selectedId)) {
      setSelectedId(null);
      setOpenSection(null);
    }
  }, [rules, selectedId]);

  const selectRule = (id, revealFlow = false) => {
    setSelectedId(id);
    setOpenSection(null);
    if (revealFlow) {
      requestAnimationFrame(() => {
        const behavior = reducedMotion ? "auto" : "smooth";
        if (window.matchMedia(STACKED_LAYOUT_QUERY).matches) {
          canvasRef.current?.scrollIntoView({ block: "start", behavior });
        } else {
          revealCanvas(behavior);
        }
      });
    }
  };
  const closeRule = () => {
    selectRefs.current.get(selectedId)?.focus();
    setSelectedId(null);
    setOpenSection(null);
  };
  const openDrawer = (id) => setOpenSection(id);
  const update = (updates) => onUpdate(rule.id, updates);
  const addRule = () => {
    selectRule(onAdd(), true);
  };

  return (
    <div ref={workspaceRef} className="arraysubs-rule-workspace">
      <aside
        className="arraysubs-rule-workspace__sidebar"
        aria-label={__("Rule list", "arraysubs")}
      >
        <div className="arraysubs-rule-workspace__guidance">
          {sidebarContent}
        </div>
        <div className="arraysubs-rule-workspace__list-heading">
          <h4>
            {__("Your rules", "arraysubs")} <span>{rules.length}</span>
          </h4>
          <p>
            {__(
              "Select a rule to edit. Drag to change its order.",
              "arraysubs",
            )}
          </p>
        </div>
        <SortableContext
          items={rules.map((item) => item.id)}
          strategy={verticalListSortingStrategy}
        >
          <div className="arraysubs-rule-workspace__list">
            {rules.map((item, index) => (
              <SortableRule
                key={item.id}
                id={item.id}
                reducedMotion={reducedMotion}
                className={`arraysubs-rule-list-item ${
                  selectedId === item.id
                    ? "arraysubs-rule-list-item--selected"
                    : ""
                } ${
                  item.enabled === false
                    ? "arraysubs-rule-list-item--disabled"
                    : ""
                }`}
              >
                {(dragHandleProps) => (
                  <>
                    <div className="arraysubs-rule-list-item__heading">
                      <button
                        type="button"
                        className="arraysubs-rule-builder__rule-drag"
                        {...dragHandleProps}
                        disabled={rules.length < 2}
                        aria-label={sprintf(
                          /* translators: %s: rule or item name. */ __("Drag to reorder %s", "arraysubs"),
                          item.name || ruleLabel,
                        )}
                        title={__(
                          "Drag to reorder. Use Space and arrow keys with a keyboard.",
                          "arraysubs",
                        )}
                      >
                        <GripVertical size={16} aria-hidden="true" />
                      </button>
                      <label className="arraysubs-rule-builder__rule-toggle">
                        <input
                          type="checkbox"
                          checked={item.enabled !== false}
                          onChange={() => onToggle(item.id)}
                          aria-label={sprintf(
                            /* translators: %s: rule name. */ __("Enable %s", "arraysubs"),
                            item.name || ruleLabel,
                          )}
                        />
                        <span className="arraysubs-rule-builder__toggle-slider" />
                      </label>
                      <span className="arraysubs-rule-list-item__number">
                        #{index + 1}
                      </span>
                      <input
                        type="text"
                        className="arraysubs-rule-list-item__name"
                        value={item.name || ""}
                        onChange={(event) =>
                          onUpdate(item.id, { name: event.target.value })
                        }
                        onFocus={() => selectRule(item.id)}
                        aria-label={sprintf(
                          /* translators: %d: rule number. */ __("Rule %d name", "arraysubs"),
                          index + 1,
                        )}
                        placeholder={__("Rule name", "arraysubs")}
                      />
                    </div>
                    <div className="arraysubs-rule-list-item__footer">
                      <button
                        ref={(element) =>
                          element
                            ? selectRefs.current.set(item.id, element)
                            : selectRefs.current.delete(item.id)
                        }
                        type="button"
                        className="arraysubs-rule-list-item__select"
                        onClick={() => selectRule(item.id, true)}
                        aria-pressed={selectedId === item.id}
                        aria-controls={flowId}
                        aria-label={sprintf(
                          /* translators: %s: item name. */ __("Edit %s", "arraysubs"),
                          item.name || ruleLabel,
                        )}
                      >
                        {selectedId === item.id
                          ? __("Editing rule", "arraysubs")
                          : __("Open rule", "arraysubs")}
                        <ChevronRight size={14} aria-hidden="true" />
                      </button>
                      <div className="arraysubs-rule-list-item__actions">
                        <button
                          type="button"
                          className="arraysubs-rule-builder__action-btn"
                          onClick={() => onMoveUp(index)}
                          disabled={index === 0}
                          aria-label={sprintf(
                            /* translators: %s: rule name. */ __("Move %s up", "arraysubs"),
                            item.name || ruleLabel,
                          )}
                          title={__("Move up", "arraysubs")}
                        >
                          <ChevronUp size={15} />
                        </button>
                        <button
                          type="button"
                          className="arraysubs-rule-builder__action-btn"
                          onClick={() => onMoveDown(index)}
                          disabled={index === rules.length - 1}
                          aria-label={sprintf(
                            /* translators: %s: rule name. */ __("Move %s down", "arraysubs"),
                            item.name || ruleLabel,
                          )}
                          title={__("Move down", "arraysubs")}
                        >
                          <ChevronDown size={15} />
                        </button>
                        <button
                          type="button"
                          className="arraysubs-rule-builder__action-btn"
                          onClick={() => selectRule(onDuplicate(item), true)}
                          aria-label={sprintf(
                            /* translators: %s: rule name. */ __("Duplicate %s", "arraysubs"),
                            item.name || ruleLabel,
                          )}
                          title={__("Duplicate", "arraysubs")}
                        >
                          <Copy size={15} />
                        </button>
                        <button
                          type="button"
                          className="arraysubs-rule-builder__action-btn arraysubs-rule-builder__action-btn--delete"
                          onClick={() => onDelete(item.id)}
                          aria-label={sprintf(
                            /* translators: %s: item name or type. */ __("Delete %s", "arraysubs"),
                            item.name || ruleLabel,
                          )}
                          title={__("Delete", "arraysubs")}
                        >
                          <Trash2 size={15} />
                        </button>
                      </div>
                    </div>
                  </>
                )}
              </SortableRule>
            ))}
          </div>
        </SortableContext>
        {!rules.length && (
          <p className="arraysubs-rule-workspace__no-rules">
            {__(
              "No rules yet. Add your first rule to get started.",
              "arraysubs",
            )}
          </p>
        )}
        <button
          type="button"
          className="button arraysubs-rule-workspace__add"
          onClick={addRule}
        >
          <Plus size={16} />
          {__("Add New Rule", "arraysubs")}
        </button>
      </aside>

      <section
        id={flowId}
        ref={canvasRef}
        className="arraysubs-rule-flow"
        aria-label={__("Selected rule flow", "arraysubs")}
      >
        <div ref={contentRef} className="arraysubs-rule-flow__content">
          {rule ? (
            <>
              <header className="arraysubs-rule-flow__header">
                <div>
                  <span className="arraysubs-rule-flow__eyebrow">
                    {sprintf(
                      /* translators: %d: rule number. */ __("Rule #%d", "arraysubs"),
                      rules.findIndex((item) => item.id === rule.id) + 1,
                    )}
                  </span>
                  <h3>{rule.name || ruleLabel}</h3>
                </div>
                <button
                  type="button"
                  className="arraysubs-rule-flow__close"
                  onClick={closeRule}
                  aria-label={__("Close rule", "arraysubs")}
                  title={__("Back to rule list", "arraysubs")}
                >
                  <X size={18} />
                </button>
              </header>
              <p className="arraysubs-rule-flow__instruction">
                {enabled
                  ? __("Click a step to edit its settings.", "arraysubs")
                  : __(
                      "This rule is disabled. Enable it in the list to edit its steps.",
                      "arraysubs",
                    )}
              </p>
              <div className="arraysubs-rule-flow__steps">
                {sections.map((step, index) => {
                  const Icon = step.icon;
                  const summary =
                    getSectionSummary(step.id, rule, conditionTypes) || step.hint;
                  return (
                    <React.Fragment key={step.id}>
                      {index > 0 && step.id !== "schedule" && <FlowArrow />}
                      <div
                        className={`arraysubs-rule-flow__step arraysubs-rule-flow__step--${step.id}`}
                      >
                        <span className="arraysubs-rule-flow__step-label">
                          {step.label}
                        </span>
                        <button
                          type="button"
                          className="arraysubs-rule-flow__node"
                          onClick={() => openDrawer(step.id)}
                          disabled={!enabled}
                          aria-haspopup="dialog"
                          aria-label={sprintf(
                            /* translators: %s: item name. */ __("Edit %s", "arraysubs"),
                            step.title,
                          )}
                        >
                          <span className="arraysubs-rule-flow__node-icon">
                            <Icon size={21} aria-hidden="true" />
                          </span>
                          <span className="arraysubs-rule-flow__node-content">
                            <strong>{step.title}</strong>
                            <span>{summary}</span>
                          </span>
                          <Pencil
                            size={16}
                            className="arraysubs-rule-flow__edit-icon"
                            aria-hidden="true"
                          />
                        </button>
                      </div>
                    </React.Fragment>
                  );
                })}
              </div>
              <div className="arraysubs-rule-flow__end">
                <span />
                {__("End of rule", "arraysubs")}
              </div>
            </>
          ) : (
            <div className="arraysubs-rule-flow__empty">
              <span className="arraysubs-rule-flow__empty-icon">
                <Workflow size={34} strokeWidth={1.5} />
              </span>
              <h3>{__("Select a rule to edit", "arraysubs")}</h3>
              <p>
                {__(
                  "Choose a rule from the list to see how it works, then open any step to make changes.",
                  "arraysubs",
                )}
              </p>
              <div
                className="arraysubs-rule-flow__empty-preview"
                aria-hidden="true"
              >
                <span />
                <FlowArrow />
                <span />
                <FlowArrow />
                <span />
              </div>
            </div>
          )}
        </div>
      </section>

      <Modal
        isOpen={!!rule && !!section && enabled}
        onClose={() => setOpenSection(null)}
        size="lg"
        title={section?.title}
        className="arraysubs-rule-drawer"
        externalDialogSelector=".media-modal, .mce-window, .tox-dialog-wrap, #wp-link-wrap"
      >
        {rule && section && (
          <div
            className={`arraysubs-members-access ${
              ruleType === "member_styling" ? "arraysubs-member-styling" : ""
            }`}
          >
            <div className="arraysubs-rule-drawer__context">
              <span>{rule.name || ruleLabel}</span>
              <p>{section.hint}</p>
            </div>
            <div
              className={`arraysubs-rule-builder__section arraysubs-rule-builder__section--${section.id}`}
            >
              <div className="arraysubs-rule-builder__section-content">
                {section.id === "conditions" && (
                  <ConditionBuilder
                    conditions={rule.conditions || { logic: "and", rules: [] }}
                    onChange={(conditions) => update({ conditions })}
                    conditionTypes={conditionTypes}
                  />
                )}
                {section.id === "target" && renderTargetFields?.(rule, update)}
                {section.id === "actions" && renderActionFields?.(rule, update)}
                {section.id === "schedule" && (
                  <ScheduleFields rule={rule} updateRule={update} />
                )}
              </div>
            </div>
            <footer className="arraysubs-rule-drawer__footer">
              <p>
                {__(
                  "Changes are kept in this rule. Use the page's Save button to apply them.",
                  "arraysubs",
                )}
              </p>
              <button
                type="button"
                className="button button-primary"
                onClick={() => setOpenSection(null)}
              >
                {__("Done", "arraysubs")}
              </button>
            </footer>
          </div>
        )}
      </Modal>
    </div>
  );
};

export default RuleFlowEditor;
