// Shared visual vocabulary: inline SVG icons (stroke-only, currentColor so
// they inherit the Dawn palette), the initials avatar, and the command-card
// building blocks reused across the login and contacts surfaces.
//
// Visual canon: «Боты» mockup at
// docs/design/new-direct-messages-design/project/stream-v2-dawn.jsx
// (BotsDesktop) — Dawn palette, fleet-violet accent, letter avatars,
// friendly cards, no terminal styling.

import type { ComponentChildren } from 'preact';

export const RefreshIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
    <path d="M3.5 8.5a6.5 6.5 0 0 1 11.4-3.2" stroke-linecap="round" />
    <path d="M16.5 11.5a6.5 6.5 0 0 1-11.4 3.2" stroke-linecap="round" />
    <path d="M14.6 3.2v3.5h-3.5" stroke-linecap="round" stroke-linejoin="round" />
    <path d="M5.4 16.8v-3.5h3.5" stroke-linecap="round" stroke-linejoin="round" />
  </svg>
);

// Triangle warning glyph — leads the WhatsApp-only About card (which
// carries `command-card warn` for the amber outline) and re-appears inside
// the AboutModal's risk-disclosure callout. Stroke-only so it picks up the
// amber tint via `currentColor` in either context.
export const WarningIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
    <path d="M10 3.2 L17.5 16.5 L2.5 16.5 Z" stroke-linecap="round" stroke-linejoin="round" />
    <path d="M10 8.5 L10 12" stroke-linecap="round" />
    <circle cx="10" cy="14.2" r="0.7" fill="currentColor" stroke="none" />
  </svg>
);

export const PhoneIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
    <rect x="6" y="2.5" width="8" height="15" rx="1.6" />
    <line x1="8.6" y1="14.5" x2="11.4" y2="14.5" stroke-linecap="round" />
  </svg>
);

export const QrIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
    <rect x="3" y="3" width="5" height="5" rx="0.6" />
    <rect x="12" y="3" width="5" height="5" rx="0.6" />
    <rect x="3" y="12" width="5" height="5" rx="0.6" />
    <path
      d="M12 12 H13.5 M15.5 12 H17 M12 14.5 H14 M16 14.5 H17 M12 17 H13.5 M15.5 17 H17"
      stroke-linecap="round"
    />
  </svg>
);

export const SearchIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
    <circle cx="9" cy="9" r="5.5" />
    <line x1="13.2" y1="13.2" x2="17" y2="17" stroke-linecap="round" />
  </svg>
);

export const BackIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
    <path d="M12.5 4 L6.5 10 L12.5 16" stroke-linecap="round" stroke-linejoin="round" />
  </svg>
);

export const UserIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
    <circle cx="10" cy="6.8" r="3.3" />
    <path d="M3.8 17c.9-3 3.3-4.6 6.2-4.6s5.3 1.6 6.2 4.6" stroke-linecap="round" />
  </svg>
);

export const LogoutIcon = () => (
  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
    <path d="M11 3.5 H4.5 V16.5 H11" stroke-linecap="round" stroke-linejoin="round" />
    <line x1="9" y1="10" x2="17" y2="10" stroke-linecap="round" />
    <path d="M14 7 L17 10 L14 13" stroke-linecap="round" stroke-linejoin="round" />
  </svg>
);

// --- Initials avatar --------------------------------------------------------

// Dawn accent rotation (same hues the design mock assigns to bot list
// entries). Hash by codepoints so a contact keeps its color across loads.
const AVATAR_COLORS = ['#9580ff', '#7ab6d9', '#d4b88a', '#7dd3a8', '#c08e7b', '#a59cff'];

const hashString = (s: string): number => {
  let h = 0;
  for (let i = 0; i < s.length; i += 1) {
    h = (h * 31 + s.charCodeAt(i)) | 0; // eslint-disable-line no-bitwise
  }
  return Math.abs(h);
};

export const avatarColor = (key: string): string =>
  AVATAR_COLORS[hashString(key) % AVATAR_COLORS.length];

export const initialsOf = (name: string | undefined, fallback = '?'): string => {
  const trimmed = (name ?? '').trim();
  if (!trimmed) return fallback;
  const parts = trimmed.split(/\s+/).filter(Boolean);
  if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
  return trimmed.slice(0, 1).toUpperCase();
};

type AvatarProps = { name?: string; colorKey: string; size?: number; src?: string | null };

// Initials always render underneath; the photo (when the MSC4039 download
// resolved) layers on top, so a slow or failed download degrades to the
// colored-letter look instead of an empty box.
export const Avatar = ({ name, colorKey, size = 38, src }: AvatarProps) => (
  <span
    class="avatar"
    aria-hidden="true"
    style={{
      width: `${size}px`,
      height: `${size}px`,
      fontSize: `${Math.round(size * 0.42)}px`,
      background: avatarColor(colorKey),
    }}
  >
    {initialsOf(name)}
    {src ? <img class="avatar-img" src={src} alt="" loading="lazy" /> : null}
  </span>
);

// --- Command card -----------------------------------------------------------

type CommandCardProps = {
  icon: ComponentChildren;
  name: string;
  desc: string;
  onClick: () => void;
  danger?: boolean;
  /** Amber accent — the WhatsApp About card signalling the Meta-ToS risk
   * disclosure behind it. */
  warn?: boolean;
  disabled?: boolean;
  spinning?: boolean;
};

export const CommandCard = ({
  icon,
  name,
  desc,
  onClick,
  danger,
  warn,
  disabled,
  spinning,
}: CommandCardProps) => (
  <button
    class={`command-card${danger ? ' danger' : ''}${warn ? ' warn' : ''}${
      spinning ? ' refreshing' : ''
    }`}
    type="button"
    onClick={onClick}
    disabled={disabled}
  >
    <span class="command-card-lead-icon" aria-hidden="true">
      {icon}
    </span>
    <div class="command-card-body">
      <div class="command-card-name">{name}</div>
      <div class="command-card-desc">{desc}</div>
    </div>
    <span class="command-card-chevron" aria-hidden="true">
      ›
    </span>
  </button>
);

// --- Status / notice --------------------------------------------------------

type StatusPillProps = {
  tone: 'connected' | 'disconnected' | 'checking';
  children: ComponentChildren;
};

export const StatusPill = ({ tone, children }: StatusPillProps) => (
  <span class={`section-status ${tone}`} role="status">
    <span class="dot" />
    {children}
  </span>
);

type NoticeProps = {
  tone: 'error' | 'warn' | 'info';
  children: ComponentChildren;
  onDismiss?: () => void;
};

// Inline notice strip — the replacement for the old transcript pane. One
// line of feedback right where the action happened, dismissable, no log.
export const Notice = ({ tone, children, onDismiss }: NoticeProps) => (
  <div class={`notice ${tone}`} role={tone === 'error' ? 'alert' : 'status'}>
    <span class="notice-body">{children}</span>
    {onDismiss ? (
      <button type="button" class="notice-dismiss" onClick={onDismiss} aria-label="×">
        ×
      </button>
    ) : null}
  </div>
);

export const Spinner = () => <span class="spinner" aria-hidden="true" />;
