/**
 * SlideshowSubPanels — internal sub-surface components for SlideshowPanel.
 * Not exported from the package index; used only by SlideshowPanel.tsx.
 */

import { useState, useCallback, useId } from "react";
import type { SlideRef, SlideHotspot, SlideSequence } from "@hyperframes/core/slideshow";
import type { DomEditSelection } from "../editor/domEditing";
import type { SceneInfo } from "./slideshowPanelHelpers";
import { generateId } from "../../utils/generateId";

// ── Section header (accordion toggle) ────────────────────────────────────

export function SectionHeader({
  children,
  expanded,
  onToggle,
}: {
  children: React.ReactNode;
  expanded: boolean;
  onToggle: () => void;
}) {
  return (
    <button
      type="button"
      className="flex w-full items-center justify-between px-3 py-2 text-[11px] font-medium text-neutral-400 hover:text-neutral-200 border-b border-neutral-800 transition-colors"
      onClick={onToggle}
      aria-expanded={expanded}
    >
      <span>{children}</span>
      <span className="text-[10px] text-neutral-600">{expanded ? "▲" : "▼"}</span>
    </button>
  );
}

// ── Sub-surface: Slide List ──────────────────────────────────────────────

export interface SlideListProps {
  scenes: SceneInfo[];
  slides: SlideRef[];
  selectedSceneId: string | null;
  onSelect: (sceneId: string) => void;
  onToggle: (sceneId: string) => void;
  onReorder: (sceneId: string, dir: "up" | "down") => void;
}

export function SlideList({
  scenes,
  slides,
  selectedSceneId,
  onSelect,
  onToggle,
  onReorder,
}: SlideListProps) {
  const slideIds = new Set(slides.map((s) => s.sceneId));
  const sceneById = new Map(scenes.map((s) => [s.id, s]));
  const orderedSlideScenes = slides
    .map((sl) => sceneById.get(sl.sceneId))
    .filter((s): s is SceneInfo => s !== undefined);
  const nonSlideScenes = scenes.filter((sc) => !slideIds.has(sc.id));
  const rows = [...orderedSlideScenes, ...nonSlideScenes];
  return (
    <div className="flex flex-col gap-px">
      {rows.map((scene) => {
        const isSlide = slideIds.has(scene.id);
        const isSelected = selectedSceneId === scene.id;
        return (
          <div
            key={scene.id}
            role="button"
            tabIndex={0}
            aria-pressed={isSelected}
            className={`flex items-center gap-2 px-3 py-1.5 rounded cursor-pointer text-[11px] transition-colors ${
              isSelected
                ? "bg-studio-accent/20 text-white"
                : "hover:bg-neutral-800/60 text-neutral-300"
            }`}
            onClick={() => onSelect(scene.id)}
            onKeyDown={(e) => {
              if (e.key === "Enter" || e.key === " ") {
                e.preventDefault();
                onSelect(scene.id);
              }
            }}
          >
            <input
              type="checkbox"
              aria-label={`Include ${scene.label} as main-line slide`}
              checked={isSlide}
              onChange={() => onToggle(scene.id)}
              onClick={(e) => e.stopPropagation()}
              className="accent-studio-accent flex-shrink-0"
            />
            <span className="flex-1 truncate">{scene.label || scene.id}</span>
            {isSlide && (
              <span className="flex gap-0.5 flex-shrink-0">
                <button
                  type="button"
                  aria-label="Move slide up"
                  title="Move up"
                  className="px-1 py-0.5 text-[10px] text-neutral-400 hover:text-white disabled:opacity-30"
                  onClick={(e) => {
                    e.stopPropagation();
                    onReorder(scene.id, "up");
                  }}
                >
                  ▲
                </button>
                <button
                  type="button"
                  aria-label="Move slide down"
                  title="Move down"
                  className="px-1 py-0.5 text-[10px] text-neutral-400 hover:text-white disabled:opacity-30"
                  onClick={(e) => {
                    e.stopPropagation();
                    onReorder(scene.id, "down");
                  }}
                >
                  ▼
                </button>
              </span>
            )}
          </div>
        );
      })}
      {scenes.length === 0 && (
        <p className="px-3 py-2 text-[11px] text-neutral-500 italic">No scenes found</p>
      )}
    </div>
  );
}

// ── Sub-surface: Slide Inspector ─────────────────────────────────────────

export interface SlideInspectorProps {
  sceneId: string;
  slide: SlideRef | undefined;
  currentTime: number;
  onSetNotes: (notes: string) => void;
  onMarkFragment: () => void;
  onRemoveFragment: (time: number) => void;
}

// fallow-ignore-next-line complexity
export function SlideInspector({
  sceneId,
  slide,
  currentTime,
  onSetNotes,
  onMarkFragment,
  onRemoveFragment,
}: SlideInspectorProps) {
  const fragments = slide?.fragments ?? [];
  return (
    <div className="flex flex-col gap-3 px-3 py-2">
      <p className="text-[10px] text-neutral-500 font-medium uppercase tracking-wide truncate">
        Scene: {sceneId}
      </p>
      <div className="flex flex-col gap-1">
        <label className="text-[11px] text-neutral-400">Notes</label>
        <textarea
          className="bg-neutral-800 border border-neutral-700 rounded px-2 py-1.5 text-[11px] text-white resize-none placeholder-neutral-600 focus:border-studio-accent/60 focus:outline-none"
          rows={3}
          placeholder="Speaker notes or script..."
          value={slide?.notes ?? ""}
          onChange={(e) => onSetNotes(e.target.value)}
        />
      </div>
      <div className="flex flex-col gap-1.5">
        <div className="flex items-center justify-between">
          <span className="text-[11px] text-neutral-400">Fragment hold-points</span>
          <button
            type="button"
            className="text-[10px] px-2 py-0.5 rounded bg-neutral-700 hover:bg-neutral-600 text-neutral-200 transition-colors"
            onClick={onMarkFragment}
            title={`Mark ${currentTime.toFixed(2)}s as hold-point`}
          >
            Mark {currentTime.toFixed(2)}s
          </button>
        </div>
        {fragments.length > 0 ? (
          <div className="flex flex-wrap gap-1">
            {fragments.map((t, i) => (
              <span
                key={`frag-${i}`}
                className="inline-flex items-center gap-1 bg-neutral-700 rounded px-1.5 py-0.5 text-[10px] text-neutral-200"
              >
                {t.toFixed(2)}s
                <button
                  type="button"
                  aria-label={`Remove fragment at ${t.toFixed(2)}s`}
                  className="text-neutral-400 hover:text-red-400 transition-colors"
                  onClick={() => onRemoveFragment(t)}
                >
                  ×
                </button>
              </span>
            ))}
          </div>
        ) : (
          <p className="text-[10px] text-neutral-600 italic">No hold-points yet</p>
        )}
      </div>
    </div>
  );
}

// ── Sub-surface: Branch Tree ──────────────────────────────────────────────

export interface BranchTreeProps {
  sequences: SlideSequence[];
  scenes: SceneInfo[];
  onCreateSequence: (label: string) => void;
  onRenameSequence: (id: string, label: string) => void;
  onDeleteSequence: (id: string) => void;
  onAssign: (sequenceId: string, sceneId: string, assign: boolean) => void;
  selectedSceneId: string | null;
  selectedSequenceId: string | null;
  onSelectBranchSlide: (sequenceId: string, sceneId: string) => void;
}

export function BranchTree({
  sequences,
  scenes,
  onCreateSequence,
  onRenameSequence,
  onDeleteSequence,
  onAssign,
  selectedSceneId,
  selectedSequenceId,
  onSelectBranchSlide,
}: BranchTreeProps) {
  const [newLabel, setNewLabel] = useState("");
  const inputId = useId();

  const handleCreate = useCallback(() => {
    const label = newLabel.trim();
    if (!label) return;
    onCreateSequence(label);
    setNewLabel("");
  }, [newLabel, onCreateSequence]);

  return (
    <div className="flex flex-col gap-3 px-3 py-2">
      <div className="flex gap-1.5">
        <input
          id={inputId}
          type="text"
          className="flex-1 bg-neutral-800 border border-neutral-700 rounded px-2 py-1 text-[11px] text-white placeholder-neutral-600 focus:border-studio-accent/60 focus:outline-none"
          placeholder="New branch name..."
          value={newLabel}
          onChange={(e) => setNewLabel(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === "Enter") handleCreate();
          }}
          aria-label="New branch sequence name"
        />
        <button
          type="button"
          className="px-2 py-1 rounded bg-neutral-700 hover:bg-neutral-600 text-[11px] text-neutral-200 transition-colors flex-shrink-0"
          onClick={handleCreate}
        >
          Add
        </button>
      </div>

      {sequences.length === 0 ? (
        <p className="text-[10px] text-neutral-600 italic">No branches yet</p>
      ) : (
        <div className="flex flex-col gap-3">
          {sequences.map((seq) => (
            <BranchItem
              key={seq.id}
              seq={seq}
              scenes={scenes}
              onRename={onRenameSequence}
              onDelete={onDeleteSequence}
              onAssign={onAssign}
              selectedSceneId={selectedSceneId}
              selectedSequenceId={selectedSequenceId}
              onSelectBranchSlide={onSelectBranchSlide}
            />
          ))}
        </div>
      )}
    </div>
  );
}

interface BranchItemProps {
  seq: SlideSequence;
  scenes: SceneInfo[];
  onRename: (id: string, label: string) => void;
  onDelete: (id: string) => void;
  onAssign: (sequenceId: string, sceneId: string, assign: boolean) => void;
  selectedSceneId: string | null;
  selectedSequenceId: string | null;
  onSelectBranchSlide: (sequenceId: string, sceneId: string) => void;
}

function BranchItem({
  seq,
  scenes,
  onRename,
  onDelete,
  onAssign,
  selectedSceneId,
  selectedSequenceId,
  onSelectBranchSlide,
}: BranchItemProps) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(seq.label);

  const commitRename = useCallback(() => {
    const label = draft.trim();
    if (label && label !== seq.label) onRename(seq.id, label);
    setEditing(false);
  }, [draft, onRename, seq.id, seq.label]);

  return (
    <div className="border border-neutral-700/60 rounded p-2 flex flex-col gap-2">
      <div className="flex items-center gap-1">
        {editing ? (
          <input
            className="flex-1 bg-neutral-800 border border-neutral-600 rounded px-1.5 py-0.5 text-[11px] text-white focus:border-studio-accent/60 focus:outline-none"
            value={draft}
            autoFocus
            onChange={(e) => setDraft(e.target.value)}
            onBlur={commitRename}
            onKeyDown={(e) => {
              if (e.key === "Enter") commitRename();
              if (e.key === "Escape") setEditing(false);
            }}
            aria-label={`Rename branch ${seq.label}`}
          />
        ) : (
          <span
            role="button"
            tabIndex={0}
            className="flex-1 text-[11px] text-white font-medium truncate cursor-pointer hover:text-neutral-300"
            title="Click to rename"
            onClick={() => setEditing(true)}
            onKeyDown={(e) => {
              if (e.key === "Enter" || e.key === " ") setEditing(true);
            }}
          >
            {seq.label}
          </span>
        )}
        <button
          type="button"
          aria-label={`Delete branch ${seq.label}`}
          className="text-[10px] text-neutral-500 hover:text-red-400 transition-colors px-1"
          onClick={() => onDelete(seq.id)}
        >
          ✕
        </button>
      </div>
      <div className="flex flex-col gap-px pl-2">
        {scenes.map((scene) => {
          const assigned = seq.slides.some((s) => s.sceneId === scene.id);
          const isSelected = selectedSequenceId === seq.id && selectedSceneId === scene.id;
          return (
            <div
              key={scene.id}
              className="flex items-center gap-1.5 py-0.5 text-[11px] text-neutral-400"
            >
              <input
                type="checkbox"
                aria-label={`Assign ${scene.label || scene.id} to branch ${seq.label}`}
                checked={assigned}
                onChange={(e) => onAssign(seq.id, scene.id, e.target.checked)}
                className="accent-studio-accent flex-shrink-0"
              />
              {assigned ? (
                <button
                  type="button"
                  aria-pressed={isSelected}
                  className={`flex-1 text-left truncate transition-colors hover:text-neutral-200 ${
                    isSelected ? "text-white" : "text-neutral-400"
                  }`}
                  onClick={() => onSelectBranchSlide(seq.id, scene.id)}
                >
                  {scene.label || scene.id}
                </button>
              ) : (
                <span className="flex-1 truncate">{scene.label || scene.id}</span>
              )}
            </div>
          );
        })}
        {scenes.length === 0 && <p className="text-[10px] text-neutral-600 italic">No scenes</p>}
      </div>
    </div>
  );
}

// ── Sub-surface: Hotspot Tool ─────────────────────────────────────────────

export interface HotspotToolProps {
  selectedSceneId: string | null;
  slide: SlideRef | undefined;
  domEditSelection: DomEditSelection | null;
  sequences: SlideSequence[];
  onAddHotspot: (sceneId: string, hotspot: SlideHotspot) => void;
  onRemoveHotspot: (sceneId: string, hotspotId: string) => void;
}

// fallow-ignore-next-line complexity
export function HotspotTool({
  selectedSceneId,
  slide,
  domEditSelection,
  sequences,
  onAddHotspot,
  onRemoveHotspot,
}: HotspotToolProps) {
  const [targetSequenceId, setTargetSequenceId] = useState("");
  const [hotspotLabel, setHotspotLabel] = useState("");
  const hotspots = slide?.hotspots ?? [];

  const selectedElementId = domEditSelection?.element?.id ?? null;
  const selectedHfId = domEditSelection?.hfId ?? null;
  const elementKey = selectedElementId || selectedHfId;

  // fallow-ignore-next-line complexity
  const handleMakeHotspot = useCallback(() => {
    if (!selectedSceneId || !targetSequenceId || !elementKey) return;
    const id = `hotspot-${elementKey}-${generateId()}`;
    const label = hotspotLabel.trim() || elementKey;
    onAddHotspot(selectedSceneId, { id, label, target: targetSequenceId });
    setHotspotLabel("");
  }, [selectedSceneId, targetSequenceId, elementKey, hotspotLabel, onAddHotspot]);

  if (!selectedSceneId) {
    return (
      <div className="px-3 py-2">
        <p className="text-[11px] text-neutral-500 italic">Select a scene in the Slides list</p>
      </div>
    );
  }

  return (
    <div className="flex flex-col gap-3 px-3 py-2">
      <div className="flex flex-col gap-1.5">
        <p className="text-[11px] text-neutral-400">
          Selected element:{" "}
          <span className="text-neutral-200 font-mono">{elementKey ?? "none"}</span>
        </p>
        <label className="text-[11px] text-neutral-400">Hotspot label</label>
        <input
          type="text"
          className="bg-neutral-800 border border-neutral-700 rounded px-2 py-1 text-[11px] text-white placeholder-neutral-600 focus:border-studio-accent/60 focus:outline-none"
          placeholder="Button label..."
          value={hotspotLabel}
          onChange={(e) => setHotspotLabel(e.target.value)}
          aria-label="Hotspot label"
        />
        <label className="text-[11px] text-neutral-400">Target branch</label>
        <select
          className="bg-neutral-800 border border-neutral-700 rounded px-2 py-1 text-[11px] text-white focus:border-studio-accent/60 focus:outline-none"
          value={targetSequenceId}
          onChange={(e) => setTargetSequenceId(e.target.value)}
          aria-label="Target branch sequence"
        >
          <option value="">— select branch —</option>
          {sequences.map((seq) => (
            <option key={seq.id} value={seq.id}>
              {seq.label}
            </option>
          ))}
        </select>
        <button
          type="button"
          disabled={!elementKey || !targetSequenceId}
          className="px-3 py-1.5 rounded bg-studio-accent/80 hover:bg-studio-accent text-white text-[11px] font-medium transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
          onClick={handleMakeHotspot}
        >
          Make hotspot
        </button>
      </div>

      {hotspots.length > 0 && (
        <div className="flex flex-col gap-1.5">
          <p className="text-[11px] text-neutral-400 font-medium">Hotspots on this slide</p>
          {hotspots.map((h) => {
            const seqLabel = sequences.find((s) => s.id === h.target)?.label ?? h.target;
            return (
              <div key={h.id} className="flex items-center gap-2 bg-neutral-800 rounded px-2 py-1">
                <span className="flex-1 text-[11px] text-neutral-200 truncate">
                  {h.label} → <span className="text-neutral-400">{seqLabel}</span>
                </span>
                <button
                  type="button"
                  aria-label={`Remove hotspot ${h.label}`}
                  className="text-[10px] text-neutral-500 hover:text-red-400 transition-colors"
                  onClick={() => onRemoveHotspot(selectedSceneId, h.id)}
                >
                  ✕
                </button>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}
