import { useTranslation } from 'react-i18next'
import { Link } from '@tanstack/react-router'
import {
  Badge,
  Button,
  Drawer,
  EmptyState,
  LoadingBlock,
  QueryErrorState,
} from '@/ui'
import { BellIcon, CheckIcon } from '@phosphor-icons/react'
import { useMyNotifications } from '@/api/queries'
import {
  useMarkAllNotificationsRead,
  useMarkNotificationRead,
} from '@/api/mutations'
import type { NotificationItem } from '@/api/client'

type Props = {
  open: boolean
  onClose: () => void
}

/**
 * Right-side drawer показывает recent notifications для current user.
 * Rendered поверх TopBar bell click. Polled через {@link useMyNotifications}
 * (30s interval same как /reviews queue).
 *
 * <p>Каждая row показывает: channel icon → preview text → relative time →
 * unread dot. Click → either deep-link (e.g. /reviews/{draftId}) ИЛИ просто
 * mark-as-read inline. Backend providing `href` для approval-related events
 * (draft decision toast spec из TODO 7).
 *
 * <p>Footer: "Mark all as read" button когда есть unread; иначе hidden.
 */
export function NotificationsDrawer({ open, onClose }: Props) {
  const { t } = useTranslation()
  const q = useMyNotifications(false, 20)
  const markOne = useMarkNotificationRead()
  const markAll = useMarkAllNotificationsRead()

  const items = q.data?.items ?? []
  const totalUnread = q.data?.totalUnread ?? 0

  return (
    <Drawer
      isOpen={open}
      onClose={onClose}
      side="right"
      widthClassName="w-full max-w-md"
      title={t('notifications.title', { defaultValue: 'Уведомления' })}
      description={
        totalUnread > 0
          ? t('notifications.unreadCount', {
              count: totalUnread,
              defaultValue: `${totalUnread} непрочитанных`,
            })
          : t('notifications.allRead', { defaultValue: 'Всё прочитано' })
      }
    >
      <div className="space-y-3">
        {q.isLoading && <LoadingBlock size="md" label={t('loading')} />}
        {q.error && <QueryErrorState error={q.error} onRetry={() => q.refetch()} />}

        {!q.isLoading && !q.error && items.length === 0 && (
          <EmptyState
            icon={<BellIcon weight="duotone" size={28} />}
            title={t('notifications.empty', {
              defaultValue: 'Уведомлений пока нет',
            })}
            description={t('notifications.emptyDescription', {
              defaultValue:
                'Здесь будут уведомления о решениях по вашим черновикам и других событиях.',
            })}
          />
        )}

        {items.length > 0 && (
          <ul className="divide-y divide-line">
            {items.map((n) => (
              <NotificationRow
                key={n.id}
                item={n}
                onMarkRead={() => markOne.mutate(n.id)}
                onClose={onClose}
              />
            ))}
          </ul>
        )}

        <div className="border-t border-line pt-3 flex items-center justify-between">
          {/* Phase B: link к per-channel preferences page. Всегда visible
              (даже если unread=0 — пользователь может зайти настроить впрок). */}
          <Link
            to="/me/notifications/preferences"
            className="text-sm text-accent hover:underline"
            onClick={onClose}
          >
            {t('notifications.preferencesLink', {
              defaultValue: 'Настроить каналы →',
            })}
          </Link>
          {totalUnread > 0 && (
            <Button
              variant="secondary"
              size="sm"
              leftIcon={<CheckIcon weight="bold" size={14} />}
              onClick={() => markAll.mutate()}
              loading={markAll.isPending}
              disabled={markAll.isPending}
            >
              {t('notifications.markAllRead', {
                defaultValue: 'Прочитать все',
              })}
            </Button>
          )}
        </div>
      </div>
    </Drawer>
  )
}

function NotificationRow({
  item,
  onMarkRead,
  onClose,
}: {
  item: NotificationItem
  onMarkRead: () => void
  onClose: () => void
}) {
  const { t } = useTranslation()
  const content = (
    <div className="flex items-start gap-3 py-3 group">
      {/* Unread dot — visual cue для еще-не-прочитанных. Скрыт когда read.
          aria-label чтобы screen reader озвучил статус. */}
      <span
        aria-label={
          item.read
            ? t('notifications.read', { defaultValue: 'Прочитано' })
            : t('notifications.unread', { defaultValue: 'Непрочитано' })
        }
        className={
          'mt-1.5 size-2 shrink-0 rounded-full ' +
          (item.read ? 'bg-transparent' : 'bg-accent')
        }
      />
      <div className="min-w-0 flex-1 space-y-1">
        <div className="flex items-center gap-2 flex-wrap">
          <Badge variant={badgeVariant(item.eventType)}>
            {humanEventType(item.eventType)}
          </Badge>
          <Badge variant="outline" className="lowercase">
            {item.channel}
          </Badge>
        </div>
        <p className={'text-cell ' + (item.read ? 'text-ink-2' : 'text-ink font-medium')}>
          {item.payloadPreview}
        </p>
        <p className="text-cap text-mute tabular-nums">
          {new Date(item.sentAt).toLocaleString()}
        </p>
      </div>
      {!item.read && (
        <button
          type="button"
          onClick={(e) => {
            e.preventDefault()
            e.stopPropagation()
            onMarkRead()
          }}
          aria-label={t('notifications.markRead', {
            defaultValue: 'Отметить прочитанным',
          })}
          className="opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity text-mute hover:text-ink shrink-0"
        >
          <CheckIcon weight="bold" size={14} />
        </button>
      )}
    </div>
  )

  // Deep-link case: row is a Link, click closes drawer + navigates +
  // implicitly marks-as-read через server (backend should mark read on
  // resource load OR we add explicit POST here).
  if (item.href) {
    return (
      <li>
        <Link
          to={item.href}
          onClick={() => {
            if (!item.read) onMarkRead()
            onClose()
          }}
          className="block hover:bg-line/30 -mx-3 px-3 rounded-sm transition-colors"
        >
          {content}
        </Link>
      </li>
    )
  }
  return <li>{content}</li>
}

/**
 * Event type → Badge variant mapping. Decision-positive (approved/published)
 * → success, negative (rejected/withdrawn) → danger, neutral progress
 * (submitted/changes_requested) → info.
 */
function badgeVariant(
  eventType: string,
): 'success' | 'danger' | 'info' | 'warning' | 'default' {
  if (/Approved|Published/i.test(eventType)) return 'success'
  if (/Rejected|Withdrawn/i.test(eventType)) return 'danger'
  if (/Submitted|ChangesRequested/i.test(eventType)) return 'info'
  return 'default'
}

/**
 * Event type → short russian label для chip. Server-side resolution лучше,
 * но пока mapping inline здесь — backend payloadPreview уже несёт полный
 * человеческий текст, chip это просто категория.
 */
function humanEventType(eventType: string): string {
  const map: Record<string, string> = {
    RecordDraftSubmitted: 'submit',
    RecordDraftApproved: 'approved',
    RecordDraftRejected: 'rejected',
    RecordDraftWithdrawn: 'withdrawn',
    SchemaDraftSubmitted: 'schema submit',
    SchemaDraftApproved: 'schema approved',
    SchemaDraftRejected: 'schema rejected',
    SchemaDraftPublished: 'schema published',
  }
  return map[eventType] ?? eventType
}
