import { useMemo, useState } from 'react';
import { Link, useNavigate } from 'react-router';
import { Inbox, Trash2 } from 'lucide-react';
import {
  Button, ButtonGroup, ConfirmDialog, DataTable, EmptyState, Toggle, useToast,
} from '@cameleer/design-system';
import type { ButtonGroupItem, Column } from '@cameleer/design-system';
import { PageLoader } from '../../components/PageLoader';
import { SeverityBadge } from '../../components/SeverityBadge';
import { AlertStateChip } from '../../components/AlertStateChip';
import {
  useAlerts, useAckAlert, useBulkAckAlerts, useBulkReadAlerts, useMarkAlertRead,
  useDeleteAlert, useBulkDeleteAlerts, useRestoreAlert,
  type AlertDto,
} from '../../api/queries/alerts';
import { useCreateSilence } from '../../api/queries/alertSilences';
import { describeApiError } from '../../api/errors';
import { useAuthStore } from '../../auth/auth-store';
import { SilenceRuleMenu } from './SilenceRuleMenu';
import { severityToAccent } from './severity-utils';
import { formatRelativeTime } from './time-utils';
import { renderAlertExpanded } from './alert-expanded';
import css from './alerts-page.module.css';
import tableStyles from '../../styles/table-section.module.css';

type AlertSeverity = NonNullable<AlertDto['severity']>;
type AlertState    = NonNullable<AlertDto['state']>;

// ── Filter bar items ────────────────────────────────────────────────────────

const SEVERITY_ITEMS: ButtonGroupItem[] = [
  { value: 'CRITICAL', label: 'Critical', color: 'var(--error)'       },
  { value: 'WARNING',  label: 'Warning',  color: 'var(--warning)'     },
  { value: 'INFO',     label: 'Info',     color: 'var(--text-muted)'  },
];

const STATE_ITEMS: ButtonGroupItem[] = [
  { value: 'PENDING',  label: 'Pending',  color: 'var(--text-muted)' },
  { value: 'FIRING',   label: 'Firing',   color: 'var(--error)' },
  { value: 'RESOLVED', label: 'Resolved', color: 'var(--success)' },
];

// ── Bulk silence helper ─────────────────────────────────────────────────────

const SILENCE_PRESETS: Array<{ label: string; hours: number }> = [
  { label: '1 hour',   hours: 1  },
  { label: '8 hours',  hours: 8  },
  { label: '24 hours', hours: 24 },
];

interface SilenceRulesForSelectionProps {
  selected: Set<string>;
  rows: AlertDto[];
}

function SilenceRulesForSelection({ selected, rows }: SilenceRulesForSelectionProps) {
  const navigate = useNavigate();
  const { toast } = useToast();
  const createSilence = useCreateSilence();

  const ruleIds = useMemo(() => {
    const ids = new Set<string>();
    for (const id of selected) {
      const row = rows.find((r) => r.id === id);
      if (row?.ruleId) ids.add(row.ruleId);
    }
    return [...ids];
  }, [selected, rows]);

  if (ruleIds.length === 0) return null;

  const handlePreset = (hours: number) => async () => {
    const now = new Date();
    const results = await Promise.allSettled(
      ruleIds.map((ruleId) =>
        createSilence.mutateAsync({
          matcher: { ruleId },
          reason: 'Silenced from inbox (bulk)',
          startsAt: now.toISOString(),
          endsAt: new Date(now.getTime() + hours * 3_600_000).toISOString(),
        }),
      ),
    );
    const failed = results.filter((r) => r.status === 'rejected').length;
    if (failed === 0) {
      toast({ title: `Silenced ${ruleIds.length} rule${ruleIds.length === 1 ? '' : 's'} for ${hours}h`, variant: 'success' });
    } else {
      toast({ title: `Silenced ${ruleIds.length - failed}/${ruleIds.length} rules`, description: `${failed} failed`, variant: 'warning' });
    }
  };

  const handleCustom = () => navigate('/alerts/silences');

  return (
    <div style={{ display: 'flex', gap: 'var(--space-xs)' }}>
      {SILENCE_PRESETS.map(({ label, hours }) => (
        <Button
          key={hours}
          variant="secondary"
          size="sm"
          disabled={createSilence.isPending}
          onClick={handlePreset(hours)}
        >
          Silence {hours}h
        </Button>
      ))}
      <Button variant="ghost" size="sm" onClick={handleCustom}>
        Custom…
      </Button>
    </div>
  );
}

// ── InboxPage ───────────────────────────────────────────────────────────────

export default function InboxPage() {
  // Filter state — defaults: FIRING selected, hide-acked on, hide-read on
  const [severitySel, setSeveritySel] = useState<Set<string>>(new Set());
  const [stateSel,    setStateSel]    = useState<Set<string>>(new Set(['FIRING']));
  const [hideAcked,   setHideAcked]   = useState(true);
  const [hideRead,    setHideRead]    = useState(true);

  const { data, isLoading, error } = useAlerts({
    severity: severitySel.size ? ([...severitySel] as AlertSeverity[]) : undefined,
    state:    stateSel.size    ? ([...stateSel]    as AlertState[])    : undefined,
    acked:    hideAcked ? false : undefined,
    read:     hideRead  ? false : undefined,
    limit: 200,
  });

  // Mutations
  const ack        = useAckAlert();
  const bulkAck    = useBulkAckAlerts();
  const markRead   = useMarkAlertRead();
  const bulkRead   = useBulkReadAlerts();
  const del        = useDeleteAlert();
  const bulkDelete = useBulkDeleteAlerts();
  const restore    = useRestoreAlert();
  const { toast }  = useToast();

  // Selection
  const [selected,      setSelected]      = useState<Set<string>>(new Set());
  const [deletePending, setDeletePending] = useState<string[] | null>(null);

  // RBAC
  const roles    = useAuthStore((s) => s.roles);
  const canDelete = roles.includes('OPERATOR') || roles.includes('ADMIN');

  const rows = data ?? [];

  const allSelected  = rows.length > 0 && rows.every((r) => selected.has(r.id));
  const someSelected = selected.size > 0 && !allSelected;

  const toggleSelected = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id); else next.add(id);
      return next;
    });

  const toggleSelectAll = () =>
    setSelected(allSelected ? new Set() : new Set(rows.map((r) => r.id)));

  // Derived counts for bulk-toolbar labels
  const selectedRows   = rows.filter((r) => selected.has(r.id));
  const unackedSel     = selectedRows.filter((r) => r.ackedAt == null).map((r) => r.id);
  const unreadSel      = selectedRows.filter((r) => r.readAt  == null).map((r) => r.id);

  // "Acknowledge all firing" target (no-selection state)
  const firingUnackedIds = rows
    .filter((r) => r.state === 'FIRING' && r.ackedAt == null)
    .map((r) => r.id);
  const allUnreadIds = rows.filter((r) => r.readAt == null).map((r) => r.id);

  // ── handlers ───────────────────────────────────────────────────────────────

  const onAck = async (id: string, title?: string) => {
    try {
      await ack.mutateAsync(id);
      toast({ title: 'Acknowledged', description: title, variant: 'success' });
    } catch (e) {
      toast({ title: 'Ack failed', description: describeApiError(e), variant: 'error' });
    }
  };

  const onMarkRead = async (id: string) => {
    try {
      await markRead.mutateAsync(id);
      toast({ title: 'Marked as read', variant: 'success' });
    } catch (e) {
      toast({ title: 'Mark read failed', description: describeApiError(e), variant: 'error' });
    }
  };

  const onDeleteOne = async (id: string) => {
    try {
      await del.mutateAsync(id);
      setSelected((prev) => {
        if (!prev.has(id)) return prev;
        const next = new Set(prev);
        next.delete(id);
        return next;
      });
      // No built-in action slot in DS toast — render Undo as a Button node
      const undoNode = (
        <Button
          variant="ghost"
          size="sm"
          onClick={() =>
            restore
              .mutateAsync(id)
              .then(
                () => toast({ title: 'Restored', variant: 'success' }),
                (e: unknown) => toast({ title: 'Undo failed', description: describeApiError(e), variant: 'error' }),
              )
          }
        >
          Undo
        </Button>
      ) as unknown as string; // DS description accepts ReactNode at runtime
      toast({ title: 'Deleted', description: undoNode, variant: 'success', duration: 5000 });
    } catch (e) {
      toast({ title: 'Delete failed', description: describeApiError(e), variant: 'error' });
    }
  };

  const onBulkAck = async (ids: string[]) => {
    if (ids.length === 0) return;
    try {
      await bulkAck.mutateAsync(ids);
      setSelected(new Set());
      toast({ title: `Acknowledged ${ids.length} alert${ids.length === 1 ? '' : 's'}`, variant: 'success' });
    } catch (e) {
      toast({ title: 'Bulk ack failed', description: describeApiError(e), variant: 'error' });
    }
  };

  const onBulkRead = async (ids: string[]) => {
    if (ids.length === 0) return;
    try {
      await bulkRead.mutateAsync(ids);
      setSelected(new Set());
      toast({ title: `Marked ${ids.length} as read`, variant: 'success' });
    } catch (e) {
      toast({ title: 'Bulk read failed', description: describeApiError(e), variant: 'error' });
    }
  };

  // ── columns ────────────────────────────────────────────────────────────────

  const columns: Column<AlertDto>[] = [
    {
      key: 'select', header: '', width: '40px',
      render: (_, row) => (
        <input
          type="checkbox"
          checked={selected.has(row.id)}
          onChange={() => toggleSelected(row.id)}
          aria-label={`Select ${row.title ?? row.id}`}
          onClick={(e) => e.stopPropagation()}
        />
      ),
    },
    {
      key: 'severity', header: 'Severity', width: '110px',
      render: (_, row) =>
        row.severity ? <SeverityBadge severity={row.severity} /> : null,
    },
    {
      key: 'state', header: 'Status', width: '140px',
      render: (_, row) =>
        row.state ? <AlertStateChip state={row.state} silenced={row.silenced} /> : null,
    },
    {
      key: 'title', header: 'Title',
      render: (_, row) => {
        const unread = row.readAt == null;
        return (
          <div className={`${css.titleCell} ${unread ? css.titleCellUnread : ''}`}>
            <Link to={`/alerts/inbox/${row.id}`} onClick={() => markRead.mutate(row.id)}>
              {row.title ?? '(untitled)'}
            </Link>
            {row.message && <span className={css.titlePreview}>{row.message}</span>}
          </div>
        );
      },
    },
    {
      key: 'age', header: 'Age', width: '100px', sortable: true,
      render: (_, row) =>
        row.firedAt ? (
          <span title={row.firedAt} style={{ fontVariantNumeric: 'tabular-nums' }}>
            {formatRelativeTime(row.firedAt)}
          </span>
        ) : '—',
    },
    {
      key: 'rowActions', header: '', width: '220px',
      render: (_, row) => (
        <div style={{ display: 'flex', gap: 'var(--space-xs)', justifyContent: 'flex-end' }}>
          {row.ackedAt == null && (
            <Button
              size="sm"
              variant="secondary"
              onClick={() => onAck(row.id, row.title ?? undefined)}
              disabled={ack.isPending}
            >
              Ack
            </Button>
          )}
          {row.readAt == null && (
            <Button
              size="sm"
              variant="ghost"
              onClick={() => onMarkRead(row.id)}
              disabled={markRead.isPending}
            >
              Mark read
            </Button>
          )}
          {row.ruleId && (
            <SilenceRuleMenu
              ruleId={row.ruleId}
              ruleTitle={row.title ?? undefined}
              variant="row"
            />
          )}
          {canDelete && (
            <Button
              size="sm"
              variant="ghost"
              onClick={() => onDeleteOne(row.id)}
              disabled={del.isPending}
              aria-label="Delete alert"
            >
              <Trash2 size={14} />
            </Button>
          )}
        </div>
      ),
    },
  ];

  // ── render ─────────────────────────────────────────────────────────────────

  if (isLoading) return <PageLoader />;
  if (error)     return <div className={css.page}>Failed to load alerts: {describeApiError(error)}</div>;

  const selectedIds = Array.from(selected);

  const needsAttention = rows.filter((r) => r.readAt == null || r.ackedAt == null).length;
  const subtitle =
    selectedIds.length > 0
      ? `${selectedIds.length} selected`
      : `${needsAttention} need attention · ${rows.length} total`;

  return (
    <div className={css.page}>
      {/* ── Header ─────────────────────────────────────────────────────── */}
      <header className={css.pageHeader}>
        <div className={css.pageTitleGroup}>
          <h2 className={css.pageTitle}>Inbox</h2>
          <span className={css.pageSubtitle}>{subtitle}</span>
        </div>
        <div className={css.pageActions}>
          <ButtonGroup
            items={SEVERITY_ITEMS}
            value={severitySel}
            onChange={setSeveritySel}
          />
          <ButtonGroup
            items={STATE_ITEMS}
            value={stateSel}
            onChange={setStateSel}
          />
          <Toggle
            label="Hide acked"
            checked={hideAcked}
            onChange={(e) => setHideAcked(e.currentTarget.checked)}
          />
          <Toggle
            label="Hide read"
            checked={hideRead}
            onChange={(e) => setHideRead(e.currentTarget.checked)}
          />
        </div>
      </header>

      {/* ── Filter / bulk toolbar ───────────────────────────────────────── */}
      <div className={css.filterBar}>
        <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13, color: 'var(--text-secondary)' }}>
          <input
            type="checkbox"
            checked={allSelected}
            ref={(el) => { if (el) el.indeterminate = someSelected; }}
            onChange={toggleSelectAll}
            aria-label={allSelected ? 'Deselect all' : 'Select all'}
          />
          {allSelected ? 'Deselect all' : `Select all${rows.length ? ` (${rows.length})` : ''}`}
        </label>
        <span style={{ flex: 1 }} />

        {selectedIds.length > 0 ? (
          /* ── Bulk actions ─────────────────────────────────────────────── */
          <>
            <Button
              variant="primary"
              size="sm"
              onClick={() => onBulkAck(unackedSel)}
              disabled={unackedSel.length === 0 || bulkAck.isPending}
            >
              Acknowledge {unackedSel.length}
            </Button>
            <Button
              variant="secondary"
              size="sm"
              onClick={() => onBulkRead(unreadSel)}
              disabled={unreadSel.length === 0 || bulkRead.isPending}
            >
              Mark {unreadSel.length} read
            </Button>
            <SilenceRulesForSelection selected={selected} rows={rows} />
            {canDelete && (
              <Button
                variant="danger"
                size="sm"
                onClick={() => setDeletePending(selectedIds)}
                disabled={bulkDelete.isPending}
              >
                Delete {selectedIds.length}
              </Button>
            )}
          </>
        ) : (
          /* ── Global actions (no selection) ───────────────────────────── */
          <>
            <Button
              variant="primary"
              size="sm"
              onClick={() => onBulkAck(firingUnackedIds)}
              disabled={firingUnackedIds.length === 0 || bulkAck.isPending}
            >
              Acknowledge all firing
            </Button>
            <Button
              variant="secondary"
              size="sm"
              onClick={() => onBulkRead(allUnreadIds)}
              disabled={allUnreadIds.length === 0 || bulkRead.isPending}
            >
              Mark all read
            </Button>
          </>
        )}
      </div>

      {/* ── Table / empty ───────────────────────────────────────────────── */}
      {rows.length === 0 ? (
        <EmptyState
          icon={<Inbox size={32} />}
          title="All clear"
          description="No alerts match the current filters."
        />
      ) : (
        <div className={`${tableStyles.tableSection} ${css.tableWrap}`}>
          <DataTable<AlertDto & { id: string }>
            columns={columns as Column<AlertDto & { id: string }>[]}
            data={rows as Array<AlertDto & { id: string }>}
            sortable
            flush
            fillHeight
            pageSize={200}
            rowAccent={(row) => row.severity ? severityToAccent(row.severity) : undefined}
            expandedContent={renderAlertExpanded}
          />
        </div>
      )}

      {/* ── Bulk delete confirmation ─────────────────────────────────────── */}
      <ConfirmDialog
        open={deletePending != null}
        onClose={() => setDeletePending(null)}
        onConfirm={async () => {
          if (!deletePending) return;
          await bulkDelete.mutateAsync(deletePending);
          toast({ title: `Deleted ${deletePending.length}`, variant: 'success' });
          setDeletePending(null);
          setSelected(new Set());
        }}
        title="Delete alerts?"
        message={`Delete ${deletePending?.length ?? 0} alerts? This affects all users.`}
        confirmText="Delete"
        variant="danger"
        loading={bulkDelete.isPending}
      />
    </div>
  );
}
