import { useCallback, useEffect, useRef, useState } from 'react';
import { ArrowLeft, Check, Copy, FolderPlus, Plus, Search, Trash2, TriangleAlert } from 'lucide-react';
import { navigateToPath } from '../routing';
import { Badge, Button, Card, ConfirmDialog, Dialog, IconButton, Input, Select, Spinner } from '../components';
import {
  ApiError,
  copyTemplate,
  createTemplate,
  createTemplateGroup,
  deleteTemplate,
  deleteTemplateGroup,
  getBlockGroups,
  getBlocks,
  getTemplate,
  getTemplateGroups,
  getTemplateItemsWithMeta,
  getTemplates,
  messageFromTemplateError,
  replaceTemplate,
  type Block,
  type BlockGroup,
  type Template,
  type TemplateGroup,
  type TemplateItem
} from '../api';

const BASE_PATH = '/app/templates';

// Every start time is a five-minute increment across a full day (mirrors Blazor TemplateEditor.razor's picker).
const START_TIME_OPTIONS = Array.from({ length: 288 }, (_, index) => {
  const totalMinutes = index * 5;
  const hours = Math.floor(totalMinutes / 60);
  const minutes = totalMinutes % 60;
  const value = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:00`;
  return { label: value.slice(0, 5), value };
});

function timeToMinutes(time: string): number {
  const [hours, minutes] = time.split(':').map(Number);
  return hours * 60 + minutes;
}

function minutesToClock(totalMinutes: number): string {
  const hours = Math.floor(totalMinutes / 60);
  const minutes = totalMinutes % 60;
  return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
}

interface DraftItem {
  key: string;
  blockId: number;
  blockName: string;
  blockMinutes: number;
  startTime: string;
}

interface Draft {
  name: string;
  items: DraftItem[];
}

let keySeq = 0;
function nextKey(): string {
  keySeq += 1;
  return `item-${keySeq}`;
}

function itemFromResponse(item: TemplateItem): DraftItem {
  return {
    key: nextKey(),
    blockId: item.blockId,
    blockName: item.blockName,
    blockMinutes: item.blockMinutes,
    startTime: item.startTime
  };
}

// Mirrors ReplaceTemplateItemsHandler.TemplateItemsMustBeValid: an item's end time is its start
// time plus the assigned block's duration; two items overlap when one starts before the other ends.
function findOverlap(items: DraftItem[]): null | string {
  const spans = items.map((item) => ({
    item,
    start: timeToMinutes(item.startTime),
    end: timeToMinutes(item.startTime) + item.blockMinutes
  }));

  for (let i = 0; i < spans.length; i += 1) {
    for (let j = i + 1; j < spans.length; j += 1) {
      const a = spans[i];
      const b = spans[j];
      if (a.start < b.end && b.start < a.end) {
        return `"${a.item.blockName}" (${minutesToClock(a.start)}-${minutesToClock(a.end)}) overlaps "${b.item.blockName}" (${minutesToClock(b.start)}-${minutesToClock(b.end)})`;
      }
    }
  }

  return null;
}

// Mirrors ReplaceTemplateItemsHandler's end-of-day check: an item's end time (start + block
// duration) must not cross midnight. Exactly 24:00 is allowed; anything past it is rejected.
function findMidnightCrossing(items: DraftItem[]): null | string {
  for (const item of items) {
    const start = timeToMinutes(item.startTime);
    const end = start + item.blockMinutes;
    if (end > 24 * 60) {
      return `"${item.blockName}" (${minutesToClock(start)}-${minutesToClock(end)}) crosses midnight, which is not supported`;
    }
  }

  return null;
}

function validate(draft: Draft): null | string {
  if (!draft.name.trim()) {
    return 'Template name is required';
  }

  return findMidnightCrossing(draft.items) ?? findOverlap(draft.items);
}

type Mode = { id: number; kind: 'edit' } | { kind: 'list' };

function modeFromPath(pathname: string): Mode {
  const normalized = pathname.replace(/\/+$/, '');
  if (normalized === BASE_PATH || !normalized.startsWith(`${BASE_PATH}/`)) {
    return { kind: 'list' };
  }
  const suffix = normalized.slice(BASE_PATH.length + 1).split('/')[0];
  const id = Number(suffix);
  return Number.isInteger(id) && id > 0 ? { id, kind: 'edit' } : { kind: 'list' };
}

export function TemplatesScreen() {
  const [pathname, setPathname] = useState(() => window.location.pathname);

  useEffect(() => {
    const onPop = () => setPathname(window.location.pathname);
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  const mode = modeFromPath(pathname);

  if (mode.kind === 'list') {
    return <TemplateList key={pathname} />;
  }

  return <TemplateEditor key={pathname} templateId={mode.id} />;
}

function TemplateList() {
  const [groups, setGroups] = useState<TemplateGroup[] | null>(null);
  const [templates, setTemplates] = useState<Template[] | null>(null);
  const [error, setError] = useState<null | string>(null);
  const [groupDialogOpen, setGroupDialogOpen] = useState(false);
  const [newGroupName, setNewGroupName] = useState('');
  const [templateDialogGroup, setTemplateDialogGroup] = useState<TemplateGroup | null>(null);
  const [newTemplateName, setNewTemplateName] = useState('');
  const [copyTarget, setCopyTarget] = useState<Template | null>(null);
  const [copyGroupId, setCopyGroupId] = useState('');
  const [copyName, setCopyName] = useState('');
  const [deleteGroupTarget, setDeleteGroupTarget] = useState<TemplateGroup | null>(null);
  const [deleteTemplateTarget, setDeleteTemplateTarget] = useState<Template | null>(null);
  const [busy, setBusy] = useState(false);
  const [filter, setFilter] = useState('');
  const activeRef = useRef(true);

  const load = useCallback(() => {
    Promise.all([getTemplateGroups(), getTemplates()])
      .then(([groupData, templateData]) => {
        if (activeRef.current) {
          setGroups(groupData);
          setTemplates(templateData);
          setError(null);
        }
      })
      .catch((loadError: unknown) => {
        if (activeRef.current) {
          setError(messageFromTemplateError(loadError));
        }
      });
  }, []);

  useEffect(() => {
    activeRef.current = true;
    load();
    return () => {
      activeRef.current = false;
    };
  }, [load]);

  const createGroup = async () => {
    if (!newGroupName.trim() || busy) {
      return;
    }
    setBusy(true);
    try {
      await createTemplateGroup({ name: newGroupName.trim() });
      setGroupDialogOpen(false);
      setNewGroupName('');
      load();
    } catch (createError) {
      setError(messageFromTemplateError(createError, 'Unable to create template group'));
    } finally {
      setBusy(false);
    }
  };

  const createTemplateInGroup = async () => {
    if (!templateDialogGroup || !newTemplateName.trim() || busy) {
      return;
    }
    setBusy(true);
    try {
      const template = await createTemplate({
        templateGroupId: templateDialogGroup.id,
        name: newTemplateName.trim()
      });
      setTemplateDialogGroup(null);
      setNewTemplateName('');
      navigateToPath(`${BASE_PATH}/${template.id}`);
    } catch (createError) {
      setError(messageFromTemplateError(createError, 'Unable to create template'));
    } finally {
      setBusy(false);
    }
  };

  const confirmCopy = async () => {
    if (!copyTarget || !copyGroupId || !copyName.trim() || busy) {
      return;
    }
    setBusy(true);
    try {
      await copyTemplate(copyTarget.id, { templateGroupId: Number(copyGroupId), name: copyName.trim() });
      setCopyTarget(null);
      load();
    } catch (copyError) {
      setError(messageFromTemplateError(copyError, 'Unable to copy template'));
    } finally {
      setBusy(false);
    }
  };

  const confirmDeleteGroup = async () => {
    if (!deleteGroupTarget) {
      return;
    }
    setBusy(true);
    try {
      await deleteTemplateGroup(deleteGroupTarget.id);
      setDeleteGroupTarget(null);
      load();
    } catch (deleteError) {
      setError(messageFromTemplateError(deleteError, 'Unable to delete template group'));
    } finally {
      setBusy(false);
    }
  };

  const confirmDeleteTemplate = async () => {
    if (!deleteTemplateTarget) {
      return;
    }
    setBusy(true);
    try {
      await deleteTemplate(deleteTemplateTarget.id);
      setDeleteTemplateTarget(null);
      load();
    } catch (deleteError) {
      setError(messageFromTemplateError(deleteError, 'Unable to delete template'));
    } finally {
      setBusy(false);
    }
  };

  if (error && (!groups || !templates)) {
    return (
      <div className="ctv-collections">
        <div className="ctv-channels-error" role="alert">
          <TriangleAlert aria-hidden="true" size={15} />
          <span>{error}</span>
          <span className="ctv-channels-spacer" />
          <Button onClick={load} size="sm" variant="secondary">
            Retry
          </Button>
        </div>
      </div>
    );
  }

  if (!groups || !templates) {
    return (
      <div className="ctv-collections-loading" role="status">
        <Spinner size={18} />
        <span>Loading templates…</span>
      </div>
    );
  }

  const sortedGroups = [...groups].sort((a, b) => a.name.localeCompare(b.name));
  const groupOptions = sortedGroups.map((group) => ({ label: group.name, value: String(group.id) }));

  // Client-side filter by template name or group name, case-insensitive (parity with Blazor
  // Templates.razor's search box). A group whose own name matches keeps all of its templates;
  // otherwise only its matching templates are kept, and the group is hidden entirely if none match.
  const needle = filter.trim().toLowerCase();
  const filteredGroups = sortedGroups
    .map((group) => {
      const groupTemplates = templates
        .filter((t) => t.templateGroupId === group.id && t.id > 0)
        .sort((a, b) => a.name.localeCompare(b.name));
      if (needle === '') {
        return { group, groupTemplates };
      }
      const groupNameMatches = group.name.toLowerCase().includes(needle);
      const matchingTemplates = groupNameMatches
        ? groupTemplates
        : groupTemplates.filter((t) => t.name.toLowerCase().includes(needle));
      return groupNameMatches || matchingTemplates.length > 0
        ? { group, groupTemplates: matchingTemplates }
        : null;
    })
    .filter((entry): entry is { group: TemplateGroup; groupTemplates: Template[] } => entry !== null);

  return (
    <div className="ctv-collections">
      <div className="ctv-channels-actionbar">
        <Badge tone="neutral">{templates.length} templates</Badge>
        <span className="ctv-channels-spacer" />
        <Button
          onClick={() => {
            setNewGroupName('');
            setGroupDialogOpen(true);
          }}
          size="sm"
          startIcon={<FolderPlus aria-hidden="true" size={14} />}
        >
          New group
        </Button>
      </div>

      <div className="ctv-channels-actionbar">
        <Input
          leadingIcon={<Search aria-hidden="true" size={14} />}
          onChange={(event) => setFilter(event.target.value)}
          placeholder="Search for templates…"
          value={filter}
        />
        <span className="ctv-channels-spacer" />
      </div>

      {error && (
        <div className="ctv-channels-error" role="alert">
          <TriangleAlert aria-hidden="true" size={15} />
          <span>{error}</span>
        </div>
      )}

      {sortedGroups.length === 0 ? (
        <Card>
          <div className="ctv-collections-empty">No template groups yet. Create one to get started.</div>
        </Card>
      ) : filteredGroups.length === 0 ? (
        <Card>
          <div className="ctv-collections-empty">No templates match this filter.</div>
        </Card>
      ) : (
        filteredGroups.map(({ group, groupTemplates }) => {
          return (
            <Card
              key={group.id}
              padded={false}
              title={group.name}
              actions={
                <div style={{ display: 'flex', gap: 8 }}>
                  <Button
                    onClick={() => {
                      setNewTemplateName('');
                      setTemplateDialogGroup(group);
                    }}
                    size="sm"
                    startIcon={<Plus aria-hidden="true" size={14} />}
                    variant="secondary"
                  >
                    New template
                  </Button>
                  <IconButton
                    onClick={() => setDeleteGroupTarget(group)}
                    size="sm"
                    title="Delete group"
                    variant="ghost"
                  >
                    <Trash2 aria-hidden="true" size={14} />
                  </IconButton>
                </div>
              }
            >
              {groupTemplates.length === 0 ? (
                <div className="ctv-collections-empty">No templates in this group.</div>
              ) : (
                groupTemplates.map((template, index) => (
                  <div
                    className="ctv-settings-flush-row"
                    key={template.id}
                    style={index === 0 ? { borderTop: 'none' } : undefined}
                  >
                    <button
                      className="ctv-settings-flush-row-main ctv-settings-flush-row-title ctv-collections-linkbtn"
                      onClick={() => navigateToPath(`${BASE_PATH}/${template.id}`)}
                      type="button"
                    >
                      {template.name}
                    </button>
                    <IconButton
                      onClick={() => {
                        setCopyTarget(template);
                        setCopyGroupId(String(template.templateGroupId));
                        setCopyName(`${template.name} copy`);
                      }}
                      size="sm"
                      title="Copy template"
                      variant="ghost"
                    >
                      <Copy aria-hidden="true" size={14} />
                    </IconButton>
                    <IconButton
                      onClick={() => setDeleteTemplateTarget(template)}
                      size="sm"
                      title="Delete template"
                      variant="ghost"
                    >
                      <Trash2 aria-hidden="true" size={14} />
                    </IconButton>
                  </div>
                ))
              )}
            </Card>
          );
        })
      )}

      <Dialog
        footer={
          <>
            <Button onClick={() => setGroupDialogOpen(false)} size="sm" variant="ghost">
              Cancel
            </Button>
            <Button disabled={!newGroupName.trim() || busy} loading={busy} onClick={() => void createGroup()} size="sm">
              Create
            </Button>
          </>
        }
        onClose={() => setGroupDialogOpen(false)}
        open={groupDialogOpen}
        title="New template group"
      >
        <Input
          label="Name"
          onChange={(event) => setNewGroupName(event.target.value)}
          placeholder="Template group name"
          value={newGroupName}
        />
      </Dialog>

      <Dialog
        footer={
          <>
            <Button onClick={() => setTemplateDialogGroup(null)} size="sm" variant="ghost">
              Cancel
            </Button>
            <Button
              disabled={!newTemplateName.trim() || busy}
              loading={busy}
              onClick={() => void createTemplateInGroup()}
              size="sm"
            >
              Create
            </Button>
          </>
        }
        onClose={() => setTemplateDialogGroup(null)}
        open={templateDialogGroup !== null}
        title={templateDialogGroup ? `New template in ${templateDialogGroup.name}` : 'New template'}
      >
        <Input
          label="Name"
          onChange={(event) => setNewTemplateName(event.target.value)}
          placeholder="Template name"
          value={newTemplateName}
        />
      </Dialog>

      <Dialog
        footer={
          <>
            <Button onClick={() => setCopyTarget(null)} size="sm" variant="ghost">
              Cancel
            </Button>
            <Button
              disabled={!copyGroupId || !copyName.trim() || busy}
              loading={busy}
              onClick={() => void confirmCopy()}
              size="sm"
            >
              Copy
            </Button>
          </>
        }
        onClose={() => setCopyTarget(null)}
        open={copyTarget !== null}
        title={copyTarget ? `Copy "${copyTarget.name}"` : 'Copy template'}
      >
        <Select label="Target group" onChange={(event) => setCopyGroupId(event.target.value)} options={groupOptions} value={copyGroupId} />
        <div style={{ marginTop: 12 }}>
          <Input label="New name" onChange={(event) => setCopyName(event.target.value)} value={copyName} />
        </div>
      </Dialog>

      <ConfirmDialog
        busy={busy}
        confirmLabel="Delete"
        message={
          deleteGroupTarget
            ? `Delete group "${deleteGroupTarget.name}"? Every template in it will also be deleted. This cannot be undone.`
            : ''
        }
        onCancel={() => setDeleteGroupTarget(null)}
        onConfirm={() => void confirmDeleteGroup()}
        open={deleteGroupTarget !== null}
        title="Delete template group"
        tone="danger"
      />

      <ConfirmDialog
        busy={busy}
        confirmLabel="Delete"
        message={deleteTemplateTarget ? `Delete template "${deleteTemplateTarget.name}"? This cannot be undone.` : ''}
        onCancel={() => setDeleteTemplateTarget(null)}
        onConfirm={() => void confirmDeleteTemplate()}
        open={deleteTemplateTarget !== null}
        title="Delete template"
        tone="danger"
      />
    </div>
  );
}

function TemplateEditor({ templateId }: { templateId: number }) {
  const [template, setTemplate] = useState<Template | null>(null);
  const [draft, setDraft] = useState<Draft | null>(null);
  const [blockGroups, setBlockGroups] = useState<BlockGroup[]>([]);
  const [blocks, setBlocks] = useState<Block[]>([]);
  const [loadError, setLoadError] = useState<null | string>(null);
  const [saveError, setSaveError] = useState<null | string>(null);
  const [saving, setSaving] = useState(false);
  const [conflictOpen, setConflictOpen] = useState(false);
  const [reloadKey, setReloadKey] = useState(0);
  // Concurrency ETag (issue #253): captured from the items GET, sent as If-Match on save, and
  // replaced from the PUT response on every successful save.
  const etagRef = useRef<string | null>(null);

  const [addGroupId, setAddGroupId] = useState('');
  const [addBlockId, setAddBlockId] = useState('');
  const [addStartTime, setAddStartTime] = useState('00:00:00');

  useEffect(() => {
    let active = true;

    // Read items + ETag FIRST, then the root metadata, mirroring BlockEditor (issue #253): the ETag
    // must be no newer than every piece of versioned data the draft is built from.
    void (async () => {
      try {
        const itemsMeta = await getTemplateItemsWithMeta(templateId);
        const [templateData, groupData, blockData] = await Promise.all([
          getTemplate(templateId),
          getBlockGroups(),
          getBlocks()
        ]);
        if (!active) {
          return;
        }
        etagRef.current = itemsMeta.etag;
        setTemplate(templateData);
        setBlockGroups(groupData);
        setBlocks(blockData);
        setDraft({
          name: templateData.name,
          items: itemsMeta.data.map(itemFromResponse)
        });
      } catch (error) {
        if (active) {
          setLoadError(messageFromTemplateError(error, 'Unable to load template'));
        }
      }
    })();

    return () => {
      active = false;
    };
  }, [templateId, reloadKey]);

  if (loadError) {
    return (
      <div className="ctv-settings-error" role="alert">
        <TriangleAlert aria-hidden="true" size={16} />
        <span>{loadError}</span>
        <Button onClick={() => navigateToPath(BASE_PATH)} size="sm" variant="secondary">
          Back to templates
        </Button>
      </div>
    );
  }

  if (!draft || !template) {
    return (
      <div className="ctv-settings-loading">
        <Spinner size={18} />
        <span>Loading template…</span>
      </div>
    );
  }

  const setDraftValue = (patch: Partial<Draft>) => {
    setDraft((current) => (current ? { ...current, ...patch } : current));
  };

  const removeItem = (key: string) => {
    setDraft((current) =>
      current ? { ...current, items: current.items.filter((item) => item.key !== key) } : current
    );
  };

  // Blocks belong to a group by id; the group picker narrows the block picker's options (derived
  // during render, not via an effect, since it's a pure function of addGroupId + blocks).
  const groupOptions = [{ label: 'Select a block group…', value: '' }].concat(
    [...blockGroups].sort((a, b) => a.name.localeCompare(b.name)).map((g) => ({ label: g.name, value: String(g.id) }))
  );
  const blocksInGroup = addGroupId
    ? blocks
        .filter((b) => b.groupId === Number(addGroupId) && b.id > 0)
        .sort((a, b) => a.name.localeCompare(b.name))
    : [];
  const blockOptions = [{ label: 'Select a block…', value: '' }].concat(
    blocksInGroup.map((b) => ({ label: b.name, value: String(b.id) }))
  );

  const addItem = () => {
    if (!addBlockId) {
      return;
    }
    const block = blocks.find((b) => b.id === Number(addBlockId));
    if (!block) {
      return;
    }
    const item: DraftItem = {
      key: nextKey(),
      blockId: block.id,
      blockName: block.name,
      blockMinutes: block.minutes,
      startTime: addStartTime
    };
    setDraft((current) => (current ? { ...current, items: [...current.items, item] } : current));
  };

  const sortedItems = [...draft.items].sort((a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime));
  const validationError = validate(draft);

  const save = async () => {
    if (validationError || saving) {
      return;
    }
    setSaving(true);
    setSaveError(null);
    try {
      const { etag } = await replaceTemplate(
        templateId,
        {
          name: draft.name.trim(),
          items: draft.items.map((item) => ({ blockId: item.blockId, startTime: item.startTime }))
        },
        etagRef.current
      );
      etagRef.current = etag;
      navigateToPath(BASE_PATH);
    } catch (error) {
      if (error instanceof ApiError && error.status === 412) {
        // Another edit landed since we loaded — force a reload rather than overwriting it (#253).
        setConflictOpen(true);
      } else {
        setSaveError(messageFromTemplateError(error, 'Unable to save template'));
      }
    } finally {
      setSaving(false);
    }
  };

  const reloadAfterConflict = () => {
    setConflictOpen(false);
    setSaveError(null);
    setDraft(null);
    setTemplate(null);
    setReloadKey((key) => key + 1);
  };

  return (
    <div className="ctv-collections">
      <div className="ctv-channels-actionbar">
        <Button
          onClick={() => navigateToPath(BASE_PATH)}
          size="sm"
          startIcon={<ArrowLeft aria-hidden="true" size={14} />}
          variant="ghost"
        >
          All templates
        </Button>
        <span className="ctv-collections-detail-title">{template.groupName} / Edit template</span>
        <span className="ctv-channels-spacer" />
        {saveError && <span className="ctv-settings-savebar-error">{saveError}</span>}
        <Button
          disabled={validationError !== null || saving}
          loading={saving}
          onClick={() => void save()}
          size="sm"
          startIcon={<Check aria-hidden="true" size={14} />}
        >
          Save template
        </Button>
      </div>

      {validationError && (
        <div className="ctv-channels-error" role="alert">
          <TriangleAlert aria-hidden="true" size={15} />
          <span>{validationError}</span>
        </div>
      )}

      <Card padded={false} title="Template">
        <div className="ctv-settings-row" style={{ borderTop: 'none' }}>
          <div className="ctv-settings-row-main">
            <div className="ctv-settings-row-label">Template group</div>
          </div>
          <div className="ctv-settings-row-control" style={{ flex: '0 0 360px' }}>
            <Input disabled size="sm" value={template.groupName} />
          </div>
        </div>
        <div className="ctv-settings-row">
          <div className="ctv-settings-row-main">
            <div className="ctv-settings-row-label">Template name</div>
          </div>
          <div className="ctv-settings-row-control" style={{ flex: '0 0 360px' }}>
            <Input
              error={draft.name.trim() ? null : 'Template name is required'}
              onChange={(event) => setDraftValue({ name: event.target.value })}
              size="sm"
              value={draft.name}
            />
          </div>
        </div>
      </Card>

      <Card padded={false} title="Add content">
        <div style={{ display: 'flex', gap: 12, padding: 16, flexWrap: 'wrap', alignItems: 'flex-end' }}>
          <div style={{ minWidth: 200 }}>
            <Select
              label="Block group"
              onChange={(event) => {
                setAddGroupId(event.target.value);
                setAddBlockId('');
              }}
              options={groupOptions}
              value={addGroupId}
            />
          </div>
          <div style={{ minWidth: 200 }}>
            <Select
              label="Block"
              onChange={(event) => setAddBlockId(event.target.value)}
              options={blockOptions}
              value={addBlockId}
            />
          </div>
          <div style={{ minWidth: 140 }}>
            <Select
              label="Start time"
              onChange={(event) => setAddStartTime(event.target.value)}
              options={START_TIME_OPTIONS}
              value={addStartTime}
            />
          </div>
          <Button disabled={!addBlockId} onClick={addItem} size="sm" startIcon={<Plus aria-hidden="true" size={14} />}>
            Add
          </Button>
        </div>
      </Card>

      <Card padded={false} title="Template items">
        {sortedItems.length === 0 ? (
          <div className="ctv-collections-empty">No items yet. Add one above to build the template.</div>
        ) : (
          <table className="ctv-channels-table">
            <thead>
              <tr>
                <th>Time</th>
                <th>Block</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {sortedItems.map((item) => {
                const start = timeToMinutes(item.startTime);
                const end = start + item.blockMinutes;
                return (
                  <tr key={item.key}>
                    <td>
                      {minutesToClock(start)}-{minutesToClock(end)}
                    </td>
                    <td>{item.blockName}</td>
                    <td>
                      <IconButton onClick={() => removeItem(item.key)} size="sm" title="Remove" variant="ghost">
                        <Trash2 aria-hidden="true" size={14} />
                      </IconButton>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </Card>

      <ConfirmDialog
        cancelLabel="Keep editing"
        confirmLabel="Reload"
        message="This template was changed elsewhere since you opened it. Reload to get the latest version — your unsaved changes will be discarded."
        onCancel={() => setConflictOpen(false)}
        onConfirm={reloadAfterConflict}
        open={conflictOpen}
        title="Template changed elsewhere"
        tone="danger"
      />
    </div>
  );
}
