import { CodeIcon, LinkIcon } from 'lucide-react';
import { useEffect, useMemo, useState, type KeyboardEvent as ReactKeyboardEvent, type SyntheticEvent } from 'react';
import type { Link } from '../lib/api';
import { safeLinkTargetUrl } from '../lib/url';

type SortField = 'alias' | 'linkType' | 'targetUrl' | 'clickCount' | 'updatedAt';
type SortDir = 'asc' | 'desc';
type ViewStyle = 'list' | 'cards';

const PAGE_SIZE = 100;
const VIEW_QUERY_PARAM = 'view';

const SORT_LABELS: Record<SortField, string> = {
  alias: 'Alias',
  linkType: 'Type',
  targetUrl: 'Target',
  clickCount: 'Clicks',
  updatedAt: 'Updated',
};

interface LinkTableProps {
  readonly links: Link[];
  readonly loading?: boolean;
  readonly error?: string | null;
  readonly emptyMessage?: string;
  readonly selectable?: boolean;
  readonly selectedIds?: ReadonlySet<string>;
  readonly onToggleSelect?: (id: string) => void;
  readonly onSelectAll?: (ids: string[]) => void;
  readonly onEdit?: (link: Link) => void;
  readonly onDelete?: (link: Link) => void;
  /** Controls Edit/Delete actions. View is always shown. Defaults to true. */
  readonly actions?: boolean;
}

function readViewStyleFromHash(): ViewStyle {
  const hash = window.location.hash.startsWith('#') ? window.location.hash.slice(1) : window.location.hash;
  const [, query = ''] = hash.split('?');
  return new URLSearchParams(query).get(VIEW_QUERY_PARAM) === 'cards' ? 'cards' : 'list';
}

function writeViewStyleToHash(viewStyle: ViewStyle) {
  const hash = window.location.hash || '#/';
  const hashBody = hash.startsWith('#') ? hash.slice(1) : hash;
  const [pathPart, query = ''] = hashBody.split('?');
  const params = new URLSearchParams(query);

  if (viewStyle === 'cards') {
    params.set(VIEW_QUERY_PARAM, viewStyle);
  } else {
    params.delete(VIEW_QUERY_PARAM);
  }

  const path = pathPart || '/';
  const nextQuery = params.toString();
  const nextHash = `#${path}${nextQuery ? `?${nextQuery}` : ''}`;

  if (window.location.hash !== nextHash) {
    window.history.replaceState(null, '', `${window.location.pathname}${window.location.search}${nextHash}`);
  }
}

function SortIndicator({ field, sortField, sortDir }: { field: SortField; sortField: SortField; sortDir: SortDir }) {
  if (field !== sortField) return <span className="sort-icon sort-icon--idle">↕</span>;
  return <span className="sort-icon">{sortDir === 'asc' ? '↑' : '↓'}</span>;
}

function navigateToLinkDetail(link: Pick<Link, 'id' | 'scope'>) {
  window.location.hash = `/links/${link.scope}/${encodeURIComponent(link.id)}`;
}

function stopRowNavigation(event: SyntheticEvent<HTMLElement>) {
  event.stopPropagation();
}

function handleRowKeyDown(event: ReactKeyboardEvent<HTMLElement>, link: Pick<Link, 'id' | 'scope'>) {
  if (event.target !== event.currentTarget) {
    return;
  }

  if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault();
    navigateToLinkDetail(link);
  }
}

function LinkTypeBadge({ linkType, className }: { linkType: Link['linkType']; className?: string }) {
  const isCustom = linkType === 'custom';
  const Icon = isCustom ? CodeIcon : LinkIcon;

  return (
    <span className={`link-type-badge ${isCustom ? 'is-custom' : 'is-redirect'}${className ? ` ${className}` : ''}`}>
      <Icon aria-hidden="true" size={14} strokeWidth={2.2} />
      <span>{isCustom ? 'Custom' : 'Redirect'}</span>
    </span>
  );
}

export default function LinkTable({
  links,
  loading = false,
  error = null,
  emptyMessage = 'No links yet.',
  selectable = false,
  selectedIds,
  onToggleSelect,
  onSelectAll,
  onEdit,
  onDelete,
  actions = true,
}: LinkTableProps) {
  const [sortField, setSortField] = useState<SortField>('updatedAt');
  const [sortDir, setSortDir] = useState<SortDir>('desc');
  const [viewStyle, setViewStyle] = useState<ViewStyle>(() => readViewStyleFromHash());
  const [visibleCount, setVisibleCount] = useState(PAGE_SIZE);

  useEffect(() => {
    const syncViewStyleFromHash = () => setViewStyle(readViewStyleFromHash());
    window.addEventListener('hashchange', syncViewStyleFromHash);
    return () => window.removeEventListener('hashchange', syncViewStyleFromHash);
  }, []);

  useEffect(() => {
    writeViewStyleToHash(viewStyle);
  }, [viewStyle]);

  const sorted = useMemo(() => {
    return [...links].sort((a, b) => {
      let cmp = 0;
      switch (sortField) {
        case 'alias':      cmp = a.alias.localeCompare(b.alias); break;
        case 'linkType':   cmp = a.linkType.localeCompare(b.linkType); break;
        case 'targetUrl':  cmp = (a.targetUrl ?? '').localeCompare(b.targetUrl ?? ''); break;
        case 'clickCount': cmp = a.clickCount - b.clickCount; break;
        case 'updatedAt':  cmp = a.updatedAt.localeCompare(b.updatedAt); break;
      }
      return sortDir === 'asc' ? cmp : -cmp;
    });
  }, [links, sortField, sortDir]);

  function handleSort(field: SortField) {
    if (field === sortField) {
      setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'));
    } else {
      setSortField(field);
      setSortDir('asc');
    }
    setVisibleCount(PAGE_SIZE);
  }

  if (loading) return <p className="table-status" aria-busy="true">Loading links…</p>;
  if (error)   return <p className="table-error" role="alert">{error}</p>;
  if (links.length === 0) return <p className="table-empty">{emptyMessage}</p>;

  const allIds = links.map((l) => l.id);
  const allSelected = selectable && selectedIds != null && allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
  const visible = sorted.slice(0, visibleCount);
  const hasMore = sorted.length > visibleCount;
  const remaining = sorted.length - visibleCount;
  const showActionColumn = actions && (onEdit != null || onDelete != null);

  return (
    <div>
      {/* Toolbar */}
      <div className="link-table-toolbar">
        <span className="muted" style={{ fontSize: '0.8125rem' }}>
          {links.length} link{links.length !== 1 ? 's' : ''}
          {visibleCount < links.length ? ` · showing ${visibleCount}` : ''}
        </span>
        <div style={{ display: 'flex', alignItems: 'center', gap: '0.35rem' }}>
          {viewStyle === 'cards' && (
            <>
              <label style={{ fontSize: '0.8rem', color: 'var(--muted)', fontWeight: 500, whiteSpace: 'nowrap' }}>Sort</label>
              <select
                value={sortField}
                onChange={(e) => { setSortField(e.target.value as SortField); setVisibleCount(PAGE_SIZE); }}
                style={{ fontSize: '0.8125rem', padding: '0.2rem 0.5rem', border: '1px solid var(--border-strong)', borderRadius: '6px', background: 'var(--surface)', color: 'var(--text)' }}
              >
                {(Object.keys(SORT_LABELS) as SortField[]).map((f) => (
                  <option key={f} value={f}>{SORT_LABELS[f]}</option>
                ))}
              </select>
              <button
                type="button"
                className="link-action"
                onClick={() => setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'))}
                title={sortDir === 'asc' ? 'Sort ascending' : 'Sort descending'}
                style={{ padding: '0.2rem 0.5rem', fontFamily: 'inherit' }}
              >
                {sortDir === 'asc' ? '↑ Asc' : '↓ Desc'}
              </button>
              <div style={{ width: '1px', height: '1.25rem', background: 'var(--border)', margin: '0 0.15rem' }} />
            </>
          )}
          <button
            type="button"
            className={`tab-button${viewStyle === 'list' ? ' is-active' : ''}`}
            onClick={() => setViewStyle('list')}
            title="List view"
          >
            ☰ List
          </button>
          <button
            type="button"
            className={`tab-button${viewStyle === 'cards' ? ' is-active' : ''}`}
            onClick={() => setViewStyle('cards')}
            title="Card view"
          >
            ⊞ Cards
          </button>
        </div>
      </div>

      {/* ── List view ── */}
      {viewStyle === 'list' && (
        <table className="link-table">
          <thead>
            <tr>
              {selectable ? (
                <th scope="col" className="col-select">
                  <input
                    type="checkbox"
                    aria-label={allSelected ? 'Deselect all links' : 'Select all links'}
                    checked={allSelected}
                    onChange={() => onSelectAll?.(allSelected ? [] : allIds)}
                  />
                </th>
              ) : null}
              {(['alias', 'linkType', 'targetUrl', 'clickCount', 'updatedAt'] as SortField[]).map((field) => (
                <th key={field} scope="col" className="sortable-th" onClick={() => handleSort(field)}>
                  {field === 'alias' ? 'Alias'
                    : field === 'linkType' ? 'Type'
                    : field === 'targetUrl' ? 'Target / content'
                    : field === 'clickCount' ? 'Clicks'
                    : 'Updated'}
                  <SortIndicator field={field} sortField={sortField} sortDir={sortDir} />
                </th>
              ))}
              {showActionColumn ? <th scope="col" className="col-actions">Actions</th> : null}
            </tr>
          </thead>
          <tbody>
            {visible.map((link) => {
              const selected = selectable && selectedIds?.has(link.id) === true;
              const shortLinkHref = `/links/${encodeURIComponent(link.id)}/go`;
              const safeUrl = link.linkType === 'redirect' ? safeLinkTargetUrl(link.targetUrl) : null;
              return (
                <tr
                  key={link.id}
                  className={`link-table-row--clickable${selected ? ' is-selected' : ''}`}
                  onClick={() => navigateToLinkDetail(link)}
                  onKeyDown={(event) => handleRowKeyDown(event, link)}
                  tabIndex={0}
                  role="link"
                  aria-label={`Open details for ${link.alias}`}
                >
                  {selectable ? (
                    <td className="col-select">
                      <input
                        type="checkbox"
                        aria-label={`Select ${link.alias}`}
                        checked={selected}
                        onClick={stopRowNavigation}
                        onChange={() => onToggleSelect?.(link.id)}
                      />
                    </td>
                  ) : null}
                  <td className="col-alias">
                    <a
                      href={shortLinkHref}
                      target="_blank"
                      rel="noreferrer noopener"
                      className="alias-pill"
                      style={{ textDecoration: 'none' }}
                      onClick={stopRowNavigation}
                    >
                      /{link.alias}
                    </a>
                    {link.description ? <small className="row-description">{link.description}</small> : null}
                  </td>
                  <td><LinkTypeBadge linkType={link.linkType} /></td>
                  <td className="col-target">
                    {link.linkType === 'redirect' ? (
                      link.targetUrl ? (
                        safeUrl
                          ? <span className="truncate" title={link.targetUrl}>{link.targetUrl}</span>
                          : <span className="muted" title="Target URL is not a valid http(s) link">Invalid target</span>
                      ) : <span className="muted">—</span>
                    ) : <span className="muted">markdown</span>}
                  </td>
                  <td className="col-clicks">{link.clickCount.toLocaleString()}</td>
                  <td className="col-updated">
                    <time dateTime={link.updatedAt}>{new Date(link.updatedAt).toLocaleDateString()}</time>
                  </td>
                  {showActionColumn ? (
                    <td className="col-actions">
                      {actions && onEdit ? (
                        <button
                          type="button"
                          className="link-action"
                          onClick={(event) => {
                            event.stopPropagation();
                            onEdit(link);
                          }}
                        >
                          Edit
                        </button>
                      ) : null}
                      {actions && onDelete ? (
                        <button
                          type="button"
                          className="link-action link-action--danger"
                          onClick={(event) => {
                            event.stopPropagation();
                            onDelete(link);
                          }}
                        >
                          Delete
                        </button>
                      ) : null}
                    </td>
                  ) : null}
                </tr>
              );
            })}
          </tbody>
        </table>
      )}

      {/* ── Cards view ── */}
      {viewStyle === 'cards' && (
        <div className="link-cards-grid">
          {visible.map((link) => {
            const selected = selectable && selectedIds?.has(link.id) === true;
            const shortLinkHref = `/links/${encodeURIComponent(link.id)}/go`;
            const safeUrl = link.linkType === 'redirect' ? safeLinkTargetUrl(link.targetUrl) : null;
            return (
              <div
                key={link.id}
                className={`link-card link-card--clickable${selected ? ' is-selected' : ''}`}
                onClick={() => navigateToLinkDetail(link)}
                onKeyDown={(event) => handleRowKeyDown(event, link)}
                tabIndex={0}
                role="link"
                aria-label={`Open details for ${link.alias}`}
              >
                <div className="link-card-header">
                  {selectable ? (
                    <input
                      type="checkbox"
                      aria-label={`Select ${link.alias}`}
                      checked={selected}
                      onClick={stopRowNavigation}
                      onChange={() => onToggleSelect?.(link.id)}
                    />
                  ) : null}
                  <a
                    href={shortLinkHref}
                    target="_blank"
                    rel="noreferrer noopener"
                    className="alias-pill"
                    style={{ textDecoration: 'none', fontSize: '0.8125rem' }}
                    onClick={stopRowNavigation}
                  >
                    /{link.alias}
                  </a>
                  <LinkTypeBadge linkType={link.linkType} className="link-card-type-badge" />
                </div>
                {link.description ? <p className="link-card-desc">{link.description}</p> : null}
                {link.linkType === 'redirect' && link.targetUrl ? (
                  <p className="link-card-url">
                    {safeUrl
                      ? <span className="truncate" title={link.targetUrl}>{link.targetUrl}</span>
                      : <span className="muted truncate">{link.targetUrl}</span>}
                  </p>
                ) : null}
                <div className="link-card-meta">
                  <span style={{ fontWeight: 600, color: 'var(--accent-text)' }}>{link.clickCount.toLocaleString()} clicks</span>
                  <time className="muted" dateTime={link.updatedAt} style={{ fontSize: '0.75rem' }}>
                    {new Date(link.updatedAt).toLocaleDateString()}
                  </time>
                </div>
                {showActionColumn ? (
                  <div className="link-card-actions">
                    {actions && onEdit ? (
                      <button
                        type="button"
                        className="link-action"
                        onClick={(event) => {
                          event.stopPropagation();
                          onEdit(link);
                        }}
                      >
                        Edit
                      </button>
                    ) : null}
                    {actions && onDelete ? (
                      <button
                        type="button"
                        className="link-action link-action--danger"
                        onClick={(event) => {
                          event.stopPropagation();
                          onDelete(link);
                        }}
                      >
                        Delete
                      </button>
                    ) : null}
                  </div>
                ) : null}
              </div>
            );
          })}
        </div>
      )}

      {/* ── Load more ── */}
      {hasMore && (
        <div style={{ textAlign: 'center', padding: '1.25rem 0 0.25rem' }}>
          <button
            type="button"
            className="link-action"
            onClick={() => setVisibleCount((c) => c + PAGE_SIZE)}
            style={{ padding: '0.5rem 2rem', fontSize: '0.875rem' }}
          >
            Load {Math.min(PAGE_SIZE, remaining)} more
            <span className="muted" style={{ marginLeft: '0.4rem', fontWeight: 400 }}>({remaining} remaining)</span>
          </button>
        </div>
      )}
    </div>
  );
}
