import { useCallback, useState, type CSSProperties, type DragEvent } from 'react';
import type { LayoutPersistence, TileSpan, TileSpec } from './types.js';
import { useWorkspaceLayout } from './useWorkspaceLayout.js';

export interface WorkspaceProps {
  /** Tile registry. */
  tiles: TileSpec[];
  /** Persistence key (route-scoped). */
  storageKey: string;
  /** Optional persistence override (default localStorage). */
  persistence?: LayoutPersistence;
  /**
   * Number of grid columns. Tiles' `span` is interpreted as a fraction
   * of this. Default 4.
   */
  columns?: 4 | 6 | 12;
  /** Show the reset-layout CTA. Default true. */
  showResetCta?: boolean;
  /** Bypass drag entirely (read-only). Default false. */
  readOnly?: boolean;
  className?: string;
  style?: CSSProperties;
}

/**
 * `<Workspace>` — drag-reorderable tile grid with width control.
 *
 * Wave 13.F.1 + .2. HTML5 native drag (no `@dnd-kit` dependency).
 * Persists via the `LayoutPersistence` adapter (default localStorage —
 * hosts on `platform-service` pass a server-backed one).
 *
 * Keyboard shortcuts on a focused tile:
 *   - ←/→  resize span down/up (clamped to 1..4)
 *   - ↑/↓  move tile up/down by one slot
 */
export function Workspace({
  tiles,
  storageKey,
  persistence,
  columns = 4,
  showResetCta = true,
  readOnly = false,
  className,
  style,
}: WorkspaceProps) {
  const { layout, move, resize, reset, hydrated } = useWorkspaceLayout(tiles, {
    storageKey,
    persistence,
  });
  const tileById = new Map(tiles.map((t) => [t.id, t]));
  const [dragIndex, setDragIndex] = useState<number | null>(null);
  const [dropIndex, setDropIndex] = useState<number | null>(null);

  const onDragStart = useCallback(
    (e: DragEvent<HTMLElement>, idx: number) => {
      if (readOnly) return;
      setDragIndex(idx);
      e.dataTransfer.effectAllowed = 'move';
      try {
        e.dataTransfer.setData('text/plain', String(idx));
      } catch {
        /* ignore */
      }
    },
    [readOnly],
  );

  const onDragOver = useCallback(
    (e: DragEvent<HTMLElement>, idx: number) => {
      if (readOnly) return;
      e.preventDefault();
      e.dataTransfer.dropEffect = 'move';
      setDropIndex(idx);
    },
    [readOnly],
  );

  const onDrop = useCallback(
    (e: DragEvent<HTMLElement>, idx: number) => {
      if (readOnly) return;
      e.preventDefault();
      const from = dragIndex;
      setDragIndex(null);
      setDropIndex(null);
      if (from === null) return;
      move(from, idx);
    },
    [dragIndex, move, readOnly],
  );

  return (
    <div data-testid="bl-workspace" className={className} style={style}>
      {showResetCta && !readOnly && (
        <div className="bl-workspace-toolbar">
          <button
            type="button"
            onClick={reset}
            data-testid="bl-workspace-reset"
            style={{
              padding: '4px 10px',
              fontSize: 12,
              borderRadius: 999,
              border: '1px solid var(--bl-border, rgba(0,0,0,0.14))',
              background: 'var(--bl-surface-card, #fff)',
              color: 'var(--bl-text-secondary, #555)',
              cursor: 'pointer',
            }}
          >
            Reset layout
          </button>
          {!hydrated && (
            <span
              data-testid="bl-workspace-hydrating"
              style={{
                marginLeft: 8,
                fontSize: 11,
                color: 'var(--bl-text-tertiary, #999)',
                fontFamily: 'ui-monospace, monospace',
              }}
            >
              loading…
            </span>
          )}
        </div>
      )}
      <div
        role="region"
        aria-label="Workspace tiles"
        data-testid="bl-workspace-grid"
        style={{
          display: 'grid',
          gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
          gap: 12,
          marginTop: 8,
        }}
      >
        {layout.entries.map((entry, idx) => {
          const tile = tileById.get(entry.id);
          if (!tile) return null;
          const span = Math.max(1, Math.min(columns, entry.span)) as TileSpan;
          return (
            <article
              key={entry.id}
              aria-label={tile.title}
              data-testid="bl-workspace-tile"
              data-tile-id={entry.id}
              data-drop-target={dropIndex === idx ? 'true' : undefined}
              tabIndex={0}
              draggable={!readOnly}
              onDragStart={(e) => onDragStart(e, idx)}
              onDragOver={(e) => onDragOver(e, idx)}
              onDragLeave={() => setDropIndex((v) => (v === idx ? null : v))}
              onDrop={(e) => onDrop(e, idx)}
              onKeyDown={(e) => {
                if (readOnly) return;
                if (e.key === 'ArrowLeft') {
                  e.preventDefault();
                  resize(entry.id, Math.max(1, span - 1) as TileSpan);
                } else if (e.key === 'ArrowRight') {
                  e.preventDefault();
                  resize(entry.id, Math.min(columns, span + 1) as TileSpan);
                } else if (e.key === 'ArrowUp') {
                  e.preventDefault();
                  move(idx, Math.max(0, idx - 1));
                } else if (e.key === 'ArrowDown') {
                  e.preventDefault();
                  move(idx, idx + 1);
                }
              }}
              style={{
                gridColumn: `span ${span}`,
                background: 'var(--bl-surface-card, #fff)',
                border: '1px solid var(--bl-border, rgba(0,0,0,0.12))',
                borderRadius: 14,
                padding: 12,
                outline:
                  dropIndex === idx
                    ? '2px dashed var(--bl-accent, #6366f1)'
                    : 'none',
                cursor: readOnly ? 'default' : 'grab',
                transition: 'outline-color 120ms ease',
              }}
            >
              <header
                style={{
                  display: 'flex',
                  alignItems: 'baseline',
                  justifyContent: 'space-between',
                  gap: 8,
                  marginBottom: 8,
                }}
              >
                <div>
                  <h4
                    style={{
                      margin: 0,
                      fontSize: 13,
                      fontWeight: 600,
                      color: 'var(--bl-text-primary, #111)',
                    }}
                  >
                    {tile.title}
                  </h4>
                  {tile.subtitle && (
                    <p
                      style={{
                        margin: '2px 0 0',
                        fontSize: 11,
                        color: 'var(--bl-text-tertiary, #999)',
                      }}
                    >
                      {tile.subtitle}
                    </p>
                  )}
                </div>
                {!readOnly && (
                  <div
                    role="group"
                    aria-label={`Resize ${tile.title}`}
                    style={{ display: 'inline-flex', gap: 2 }}
                  >
                    {([1, 2, 3, 4] as TileSpan[]).filter((n) => n <= columns).map((n) => (
                      <button
                        key={n}
                        type="button"
                        aria-pressed={span === n}
                        onClick={() => resize(entry.id, n)}
                        data-testid={`bl-workspace-tile-size-${n}`}
                        style={{
                          width: 22,
                          height: 22,
                          fontSize: 11,
                          borderRadius: 6,
                          border:
                            span === n
                              ? '1px solid var(--bl-accent, #6366f1)'
                              : '1px solid var(--bl-border, rgba(0,0,0,0.12))',
                          background:
                            span === n
                              ? 'color-mix(in srgb, var(--bl-accent, #6366f1) 16%, transparent)'
                              : 'transparent',
                          color:
                            span === n
                              ? 'var(--bl-accent, #6366f1)'
                              : 'var(--bl-text-tertiary, #999)',
                          cursor: 'pointer',
                        }}
                      >
                        {n}
                      </button>
                    ))}
                  </div>
                )}
              </header>
              <div>{tile.content}</div>
            </article>
          );
        })}
      </div>
    </div>
  );
}
