// ---------------------------------------------------------------------------
// Generic wrapper NodeView
//
// Renders any "wrapper" component from the registry as:
//   ┌──────────────────────────────────────┐
//   │ [icon]  Title / fields       [chevron]│  <- chrome (contentEditable=false)
//   ├──────────────────────────────────────┤
//   │  NodeViewContent (editable blocks)   │  <- ProseMirror content hole
//   └──────────────────────────────────────┘
// ---------------------------------------------------------------------------

import React, { useState, useCallback } from "react";
import { NodeViewWrapper, NodeViewContent } from "@tiptap/react";
import type { NodeViewProps } from "@tiptap/react";
import type { ComponentDef, ComponentField } from "./registry";

const VARIANT_COLORS: Record<string, { border: string; bg: string; icon: string }> = {
  neutral: { border: "var(--border-color)", bg: "var(--surface-bg)", icon: "📝" },
  info: { border: "#f39c12", bg: "color-mix(in oklab, #f39c12 10%, var(--surface-bg))", icon: "💡" },
  success: { border: "#2ecc71", bg: "color-mix(in oklab, #2ecc71 8%, var(--surface-bg))", icon: "✅" },
  danger: { border: "#e74c3c", bg: "color-mix(in oklab, #e74c3c 8%, var(--surface-bg))", icon: "⚠️" },
};

function FieldInput({
  field,
  value,
  onChange,
}: {
  field: ComponentField;
  value: unknown;
  onChange: (val: unknown) => void;
}) {
  if (field.type === "boolean") {
    return (
      <label
        style={{
          display: "flex",
          alignItems: "center",
          gap: 4,
          fontSize: 12,
          color: "var(--muted-color)",
          cursor: "pointer",
        }}
      >
        <input
          type="checkbox"
          checked={!!value}
          onChange={(e) => onChange(e.target.checked)}
          style={{ accentColor: "var(--primary-color)" }}
        />
        {field.label}
      </label>
    );
  }

  if (field.type === "select" && field.options) {
    return (
      <select
        value={String(value ?? field.default ?? "")}
        onChange={(e) => onChange(e.target.value)}
        style={{
          background: "var(--surface-bg)",
          border: "1px solid var(--border-color)",
          borderRadius: 4,
          color: "var(--text-color)",
          fontSize: 12,
          padding: "2px 6px",
          outline: "none",
        }}
      >
        {field.options.map((opt) => (
          <option key={opt} value={opt}>{opt}</option>
        ))}
      </select>
    );
  }

  // string field
  return (
    <input
      type="text"
      value={String(value ?? "")}
      placeholder={field.placeholder || field.label}
      onChange={(e) => onChange(e.target.value)}
      style={{
        background: "transparent",
        border: "none",
        borderBottom: "1px solid var(--border-color)",
        color: "var(--text-color)",
        fontSize: 14,
        fontWeight: 600,
        padding: "2px 0",
        outline: "none",
        flex: 1,
        minWidth: 0,
      }}
    />
  );
}

/**
 * Factory: returns a React component bound to a specific ComponentDef.
 */
export function makeWrapperView(def: ComponentDef) {
  function WrapperNodeView({ node, updateAttributes }: NodeViewProps) {
    const [collapsed, setCollapsed] = useState(
      def.name === "accordion" ? !node.attrs.open : false,
    );

    const handleFieldChange = useCallback(
      (fieldName: string, value: unknown) => {
        updateAttributes({ [fieldName]: value });
      },
      [updateAttributes],
    );

    const titleField = def.fields.find((f) => f.name === "title");
    const otherFields = def.fields.filter((f) => f.name !== "title");

    // Variant-aware styling for Note
    const variant = node.attrs.variant as string | undefined;
    const colors = def.name === "note" && variant ? VARIANT_COLORS[variant] || VARIANT_COLORS.neutral : null;

    const emoji = (node.attrs.emoji as string) || colors?.icon || def.icon;

    const borderColor = colors?.border || "var(--border-color)";
    const bgColor = colors?.bg || "var(--surface-bg)";

    const isAccordion = def.name === "accordion";
    const isNote = def.name === "note";
    const isQuote = def.name === "quoteBlock";
    const isSidenote = def.name === "sidenote";
    const isWideOrFull = def.name === "wide" || def.name === "fullWidth";

    // NOTE: for wide/fullWidth we intentionally DO NOT set any inline margin.
    // The `margin` shorthand would collapse to `margin-left: 0` and defeat the
    // CSS viewport-breakout (see article.css `.node-wide` / `.node-fullWidth`).
    // Vertical spacing for those two is applied from CSS via `margin-block`.
    const wrapperStyle: React.CSSProperties | undefined = isNote
      ? {
          borderLeft: `2px solid ${borderColor}`,
          borderTopRightRadius: 8,
          borderBottomRightRadius: 8,
          background: bgColor,
          padding: 0,
          margin: "0.75em 0",
        }
      : isQuote
        ? {
            position: "relative" as const,
            margin: "32px 0",
            maxWidth: 600,
          }
        : isSidenote
          ? {
              borderRadius: 8,
              padding: 0,
              margin: "0.75em 0",
              fontSize: "0.9rem",
              color: "var(--muted-color)",
            }
          : isWideOrFull
            ? undefined
            : {
                border: `1px solid ${borderColor}`,
                borderRadius: "var(--table-border-radius, 8px)",
                background: bgColor,
                margin: "0.75em 0",
                overflow: "hidden",
              };

    if (isSidenote) {
      return (
        <NodeViewWrapper
          data-component={def.name}
          className="sidenote-wrapper-node"
        >
          <div className="sidenote-content-area">
            <NodeViewContent className="component-content" />
          </div>
          <span contentEditable={false} className="sidenote-badge">¶</span>
        </NodeViewWrapper>
      );
    }

    return (
      <NodeViewWrapper
        data-component={def.name}
        data-variant={variant || undefined}
        style={wrapperStyle}
      >
        {/* Header chrome - not editable by ProseMirror */}
        <div
          contentEditable={false}
          style={{
            display: "flex",
            alignItems: "center",
            gap: 8,
            padding: isNote ? "8px 18px" : isQuote ? "0" : "8px 12px",
            borderBottom: collapsed || isQuote ? "none" : isNote ? "none" : `1px solid ${borderColor}`,
            userSelect: "none",
            cursor: isAccordion ? "pointer" : "default",
          }}
          onClick={isAccordion ? () => setCollapsed((c) => !c) : undefined}
        >
          <span style={{ fontSize: 14, lineHeight: 1, flexShrink: 0 }}>{emoji}</span>

          {titleField ? (
            <div
              style={{ flex: 1, minWidth: 0 }}
              onClick={(e) => e.stopPropagation()}
            >
              <FieldInput
                field={titleField}
                value={node.attrs[titleField.name]}
                onChange={(v) => handleFieldChange(titleField.name, v)}
              />
            </div>
          ) : (
            <span style={{ flex: 1, fontSize: 13, fontWeight: 600, color: "var(--muted-color)" }}>
              {def.label}
            </span>
          )}

          {otherFields.map((f) => (
            <div key={f.name} onClick={(e) => e.stopPropagation()}>
              <FieldInput
                field={f}
                value={node.attrs[f.name]}
                onChange={(v) => handleFieldChange(f.name, v)}
              />
            </div>
          ))}

          {isAccordion && (
            <span
              style={{
                fontSize: 14,
                transition: "transform 200ms ease",
                transform: collapsed ? "rotate(-90deg)" : "rotate(0deg)",
                color: "var(--muted-color)",
                flexShrink: 0,
                opacity: 0.6,
              }}
            >
              ▾
            </span>
          )}
        </div>

        {/* Editable content area */}
        <div
          style={{
            display: collapsed ? "none" : "block",
            padding: isNote ? "0 18px 12px" : isQuote ? "0" : "8px 12px",
          }}
        >
          <NodeViewContent className="component-content" />
        </div>
      </NodeViewWrapper>
    );
  }

  WrapperNodeView.displayName = `${def.tag}View`;
  return WrapperNodeView;
}
