'use client';

import { useRef } from 'react';
import { useRouter } from 'next/navigation';
import {
  ArrowLeft,
  Printer,
  Calendar,
  Users,
  Webhook,
  LayoutGrid,
  Shield,
  Database,
  Layers,
  Clock,
  BarChart3,
  Globe,
  Plug,
  CheckCircle2,
  Circle,
} from 'lucide-react';

const LAST_UPDATE = '27 февраля 2026';

/* ─────────────── data ─────────────── */

interface Feature {
  title: string;
  items: string[];
}

interface ApiEndpoint {
  method: string;
  path: string;
  desc: string;
  auth: string;
}

interface WebhookEvent {
  event: string;
  trigger: string;
  payload: string;
}

interface Sprint {
  id: number;
  name: string;
  weeks: string;
  tasks: { title: string; layer: string }[];
}

const coreFeatures: Feature[] = [
  {
    title: 'Каталог услуг',
    items: [
      'Категории услуг (иерархия): "Персональные тренировки", "Групповые занятия", "Массаж"',
      'Свойства услуги: название, описание, длительность, стоимость, тип (individual/group)',
      'Привязка к тренерам (какие тренеры могут вести услугу)',
      'Привязка к ресурсам (залы, оборудование)',
      'Вместимость (для групповых): макс. кол-во участников + дополнительные места',
      'Ограничение по абонементу (только клиенты с действующим абонементом)',
      'Флаг доступности для онлайн-записи',
    ],
  },
  {
    title: 'Управление расписанием',
    items: [
      'Рабочий график тренера: смены, перерывы, выходные (шаблон + исключения)',
      'Индивидуальные слоты: автогенерация из графика минус занятые записи',
      'Групповые события: ручное создание в журнале записей с датой/временем/вместимостью',
      'Повторяющиеся события: шаблон на неделю, повтор серии, отмена отдельного события из серии',
      'Недельное расписание: виджет (Week Schedule) для фитнес-клубов с регулярным расписанием',
      'Drag-and-drop: перенос записей в журнале календаря',
      'Мультифилиальность: сотрудник может работать в нескольких клубах',
    ],
  },
  {
    title: 'Процесс записи клиента',
    items: [
      'Индивидуальная запись: выбор услуги → тренер → дата → время → данные клиента → подтверждение',
      'Групповая запись: просмотр ближайших групповых событий → бронирование места(мест)',
      'Мультизапись: бронирование нескольких услуг/событий за один визит',
      'Верификация телефона (SMS-код) — опционально',
      'Предоплата онлайн или списание с абонемента',
      'Пробное посещение (trial visit) для новых клиентов',
      'Лист ожидания (waitlist) при заполненном расписании',
    ],
  },
  {
    title: 'Уведомления (каскадная доставка)',
    items: [
      'Создание записи: клиенту + тренеру + админу',
      'Напоминание о визите: за 24ч (email), за 1ч (push/SMS) — настраиваемое',
      'Подтверждение записи (require confirmation)',
      'Изменение / перенос записи',
      'Отмена записи (клиентом или администратором)',
      'No-show (клиент не пришёл)',
      'Приглашение записаться повторно',
      'Каналы: Push → Email → Telegram → WhatsApp → SMS (приоритет настраиваемый)',
    ],
  },
  {
    title: 'Абонементы и оплата',
    items: [
      'Типы абонементов: по визитам, безлимитный, часовой, смешанный',
      'Автосписание визитов при записи / по факту посещения',
      'Заморозка абонемента',
      'Сертификаты с номиналом (подарочные)',
      'Баланс клиента (депозит)',
      'Онлайн-оплата: ЮKassa, Т-Банк, СБП',
      'Предоплата при записи: % для индивидуальных, 100% для групповых',
    ],
  },
  {
    title: 'Аналитика и отчёты',
    items: [
      'Загруженность тренеров (отработано часов / рабочих часов)',
      'Конверсия записей (записались → пришли → повторные)',
      'Средний чек за визит / за клиента',
      'Отчёт по услугам (выручка, количество, средний чек)',
      'Отчёт по клиентам (новые, вернувшиеся, потерянные)',
      'Заполненность групповых событий',
      'Динамика по периодам (день / неделя / месяц / год)',
    ],
  },
];

const apiEndpoints: ApiEndpoint[] = [
  // Services
  { method: 'GET', path: '/booking/services', desc: 'Каталог услуг (с фильтрами)', auth: 'JWT' },
  { method: 'POST', path: '/booking/services', desc: 'Создать услугу', auth: 'JWT + CLUB_ADMIN' },
  {
    method: 'PATCH',
    path: '/booking/services/:id',
    desc: 'Обновить услугу',
    auth: 'JWT + CLUB_ADMIN',
  },
  {
    method: 'DELETE',
    path: '/booking/services/:id',
    desc: 'Удалить услугу',
    auth: 'JWT + CLUB_ADMIN',
  },
  // Service Categories
  { method: 'GET', path: '/booking/service-categories', desc: 'Категории услуг', auth: 'JWT' },
  {
    method: 'POST',
    path: '/booking/service-categories',
    desc: 'Создать категорию',
    auth: 'JWT + CLUB_ADMIN',
  },
  // Schedule
  { method: 'GET', path: '/booking/schedule', desc: 'Расписание (журнал записей)', auth: 'JWT' },
  {
    method: 'GET',
    path: '/booking/schedule/available-dates',
    desc: 'Доступные даты',
    auth: 'Public / JWT',
  },
  {
    method: 'GET',
    path: '/booking/schedule/available-slots',
    desc: 'Доступные слоты (дата+тренер+услуга)',
    auth: 'Public / JWT',
  },
  {
    method: 'GET',
    path: '/booking/staff-schedule/:staffId',
    desc: 'График работы тренера',
    auth: 'JWT',
  },
  {
    method: 'PUT',
    path: '/booking/staff-schedule/:staffId',
    desc: 'Установить график',
    auth: 'JWT + CLUB_ADMIN',
  },
  // Group Events
  {
    method: 'GET',
    path: '/booking/group-events',
    desc: 'Групповые события (с вместимостью)',
    auth: 'Public / JWT',
  },
  {
    method: 'POST',
    path: '/booking/group-events',
    desc: 'Создать групповое событие',
    auth: 'JWT + MANAGER+',
  },
  {
    method: 'PATCH',
    path: '/booking/group-events/:id',
    desc: 'Обновить событие',
    auth: 'JWT + MANAGER+',
  },
  {
    method: 'DELETE',
    path: '/booking/group-events/:id',
    desc: 'Удалить событие',
    auth: 'JWT + CLUB_ADMIN',
  },
  {
    method: 'POST',
    path: '/booking/group-events/:id/repeat',
    desc: 'Повтор серии событий',
    auth: 'JWT + MANAGER+',
  },
  // Records (Bookings)
  { method: 'GET', path: '/booking/records', desc: 'Список записей (фильтры, поиск)', auth: 'JWT' },
  {
    method: 'POST',
    path: '/booking/records',
    desc: 'Создать запись (admin)',
    auth: 'JWT + MANAGER+',
  },
  {
    method: 'PATCH',
    path: '/booking/records/:id',
    desc: 'Обновить запись (статус, перенос)',
    auth: 'JWT',
  },
  { method: 'DELETE', path: '/booking/records/:id', desc: 'Отменить запись', auth: 'JWT' },
  {
    method: 'POST',
    path: '/booking/records/:id/confirm',
    desc: 'Подтвердить запись',
    auth: 'JWT / Token',
  },
  {
    method: 'POST',
    path: '/booking/records/:id/complete',
    desc: 'Отметить выполненной',
    auth: 'JWT + TRAINER+',
  },
  {
    method: 'POST',
    path: '/booking/records/:id/no-show',
    desc: 'Отметить неявку',
    auth: 'JWT + TRAINER+',
  },
  // Online Booking (Public)
  {
    method: 'GET',
    path: '/booking/public/:clubSlug/services',
    desc: 'Услуги (виджет)',
    auth: 'API-key',
  },
  {
    method: 'GET',
    path: '/booking/public/:clubSlug/staff',
    desc: 'Тренеры (виджет)',
    auth: 'API-key',
  },
  {
    method: 'GET',
    path: '/booking/public/:clubSlug/dates',
    desc: 'Доступные даты (виджет)',
    auth: 'API-key',
  },
  {
    method: 'GET',
    path: '/booking/public/:clubSlug/times',
    desc: 'Доступные слоты (виджет)',
    auth: 'API-key',
  },
  {
    method: 'GET',
    path: '/booking/public/:clubSlug/group-events',
    desc: 'Групповые события (виджет)',
    auth: 'API-key',
  },
  {
    method: 'POST',
    path: '/booking/public/:clubSlug/book',
    desc: 'Забронировать (виджет)',
    auth: 'API-key',
  },
  {
    method: 'POST',
    path: '/booking/public/:clubSlug/verify-phone',
    desc: 'Верификация телефона',
    auth: 'API-key',
  },
  // Memberships
  { method: 'GET', path: '/booking/memberships', desc: 'Типы абонементов', auth: 'JWT' },
  {
    method: 'POST',
    path: '/booking/memberships',
    desc: 'Создать тип абонемента',
    auth: 'JWT + CLUB_ADMIN',
  },
  {
    method: 'GET',
    path: '/booking/client-memberships/:clientId',
    desc: 'Абонементы клиента',
    auth: 'JWT',
  },
  {
    method: 'POST',
    path: '/booking/client-memberships',
    desc: 'Выдать абонемент клиенту',
    auth: 'JWT + MANAGER+',
  },
  {
    method: 'POST',
    path: '/booking/client-memberships/:id/freeze',
    desc: 'Заморозить абонемент',
    auth: 'JWT + MANAGER+',
  },
  // Waitlist
  { method: 'GET', path: '/booking/waitlist', desc: 'Лист ожидания', auth: 'JWT' },
  {
    method: 'POST',
    path: '/booking/waitlist',
    desc: 'Добавить в лист ожидания',
    auth: 'JWT + MANAGER+',
  },
  {
    method: 'POST',
    path: '/booking/waitlist/:id/convert',
    desc: 'Конвертировать в запись',
    auth: 'JWT + MANAGER+',
  },
  // Analytics
  {
    method: 'GET',
    path: '/booking/analytics/occupancy',
    desc: 'Загруженность тренеров',
    auth: 'JWT + MANAGER+',
  },
  {
    method: 'GET',
    path: '/booking/analytics/conversion',
    desc: 'Конверсия записей',
    auth: 'JWT + MANAGER+',
  },
  {
    method: 'GET',
    path: '/booking/analytics/revenue',
    desc: 'Выручка по услугам',
    auth: 'JWT + CLUB_ADMIN',
  },
];

const webhookEvents: WebhookEvent[] = [
  {
    event: 'booking.record.created',
    trigger: 'Создана новая запись',
    payload: '{ record, client, service, staff, source }',
  },
  {
    event: 'booking.record.updated',
    trigger: 'Запись обновлена (перенос, данные)',
    payload: '{ record, changes, updatedBy }',
  },
  {
    event: 'booking.record.confirmed',
    trigger: 'Клиент подтвердил запись',
    payload: '{ record, confirmedAt }',
  },
  {
    event: 'booking.record.cancelled',
    trigger: 'Запись отменена',
    payload: '{ record, cancelledBy, reason }',
  },
  {
    event: 'booking.record.completed',
    trigger: 'Визит завершён',
    payload: '{ record, completedBy }',
  },
  { event: 'booking.record.noshow', trigger: 'Клиент не явился', payload: '{ record, markedBy }' },
  {
    event: 'booking.group_event.created',
    trigger: 'Создано групповое событие',
    payload: '{ event, staff, service }',
  },
  {
    event: 'booking.group_event.updated',
    trigger: 'Событие обновлено',
    payload: '{ event, changes }',
  },
  {
    event: 'booking.group_event.cancelled',
    trigger: 'Событие отменено',
    payload: '{ event, reason, affectedRecords }',
  },
  {
    event: 'booking.client.created',
    trigger: 'Новый клиент через запись',
    payload: '{ client, source }',
  },
  {
    event: 'booking.membership.activated',
    trigger: 'Абонемент активирован',
    payload: '{ membership, client }',
  },
  {
    event: 'booking.membership.depleted',
    trigger: 'Визиты по абонементу закончились',
    payload: '{ membership, client }',
  },
  {
    event: 'booking.membership.expired',
    trigger: 'Абонемент истёк',
    payload: '{ membership, client }',
  },
  {
    event: 'booking.payment.completed',
    trigger: 'Оплата проведена',
    payload: '{ payment, record, method }',
  },
  { event: 'booking.service.created', trigger: 'Создана услуга', payload: '{ service }' },
  {
    event: 'booking.service.updated',
    trigger: 'Услуга обновлена',
    payload: '{ service, changes }',
  },
  {
    event: 'booking.staff.schedule_changed',
    trigger: 'Изменён график тренера',
    payload: '{ staffId, schedule }',
  },
];

const sprints: Sprint[] = [
  {
    id: 1,
    name: 'Sprint 1 — Фундамент',
    weeks: 'Недели 1-2',
    tasks: [
      {
        title:
          'Prisma-модели: BookingService, BookingServiceCategory, BookingStaffSchedule, BookingRecord, BookingGroupEvent',
        layer: 'schema',
      },
      { title: 'Миграция БД + seed данные для тестового клуба', layer: 'schema' },
      { title: 'BookingModule (NestJS): регистрация, @RequireModule("booking")', layer: 'api' },
      { title: 'CRUD услуг: BookingServicesController + BookingServicesService', layer: 'api' },
      { title: 'CRUD категорий услуг', layer: 'api' },
      { title: 'CRUD графика тренеров: StaffScheduleService', layer: 'api' },
      { title: 'RLS: club_id во всех таблицах + TenantMiddleware', layer: 'api' },
      { title: 'RBAC: @Roles() на всех эндпоинтах, BookingPermissions', layer: 'api' },
      { title: 'Unit-тесты: сервисы услуг, категорий, графика', layer: 'test' },
    ],
  },
  {
    id: 2,
    name: 'Sprint 2 — Записи и расписание',
    weeks: 'Недели 3-4',
    tasks: [
      {
        title: 'AvailabilityService: расчёт свободных слотов (график - записи - буфер)',
        layer: 'api',
      },
      { title: 'BookingRecordsController: CRUD записей (индивидуальных)', layer: 'api' },
      {
        title: 'Статусная машина записи: PENDING → CONFIRMED → COMPLETED / CANCELLED / NO_SHOW',
        layer: 'api',
      },
      {
        title: 'GroupEventsController: создание, обновление, удаление групповых событий',
        layer: 'api',
      },
      { title: 'Запись на групповое событие: проверка вместимости, доп. места', layer: 'api' },
      { title: 'Повторяющиеся события: RepeatService (шаблон серии, отмена одного)', layer: 'api' },
      { title: 'Лист ожидания: WaitlistService (добавление, конвертация в запись)', layer: 'api' },
      { title: 'EventEmitter2: booking.record.* события для внутренних подписчиков', layer: 'api' },
      { title: 'Unit-тесты: availability, booking CRUD, group events, waitlist', layer: 'test' },
      {
        title: 'E2E-тесты: полный цикл записи (создание → подтверждение → завершение)',
        layer: 'test',
      },
    ],
  },
  {
    id: 3,
    name: 'Sprint 3 — Интеграции и события',
    weeks: 'Недели 5-6',
    tasks: [
      { title: 'REST Webhook Dispatcher: EventEmitter2 → BullMQ → HTTP POST', layer: 'api' },
      { title: 'Webhook UI: настройка URL, выбор событий, retry-логика', layer: 'api' },
      { title: 'Webhook Log: история отправок, статусы, повторные отправки', layer: 'api' },
      { title: 'Адаптер Bitrix24: маппинг событий booking.* → Bitrix REST API', layer: 'api' },
      { title: 'Адаптер 1С: маппинг событий → формат обмена 1С (XML/JSON)', layer: 'api' },
      {
        title: 'CRM-bridge: настройка "куда попадают записи в CRM" (pipeline + stage mapping)',
        layer: 'api',
      },
      {
        title: 'Уведомления: NotificationService — каскадная доставка (Push → Email → TG → SMS)',
        layer: 'api',
      },
      { title: 'Шаблоны уведомлений: настраиваемые по событию + merge fields', layer: 'api' },
      { title: 'Unit-тесты: webhook dispatch, CRM bridge, notification cascade', layer: 'test' },
    ],
  },
  {
    id: 4,
    name: 'Sprint 4 — Абонементы и оплата',
    weeks: 'Недели 7-8',
    tasks: [
      {
        title: 'Prisma-модели: BookingMembershipType, BookingClientMembership, BookingPayment',
        layer: 'schema',
      },
      {
        title: 'MembershipsService: типы абонементов (визиты, безлимит, часовой, смешанный)',
        layer: 'api',
      },
      {
        title: 'ClientMembershipsService: выдача, списание визитов, заморозка, проверка валидности',
        layer: 'api',
      },
      { title: 'Интеграция с записью: оплата абонементом при бронировании', layer: 'api' },
      { title: 'Ограничение записи: "только с абонементом" для групповых событий', layer: 'api' },
      {
        title: 'PaymentService: онлайн-предоплата (ЮKassa / Т-Банк / СБП), фискализация',
        layer: 'api',
      },
      { title: 'Баланс клиента (депозит): пополнение, списание', layer: 'api' },
      { title: 'Сертификаты: создание, продажа, использование', layer: 'api' },
      { title: 'Unit-тесты: memberships lifecycle, payment flow', layer: 'test' },
    ],
  },
  {
    id: 5,
    name: 'Sprint 5 — Публичный API и виджет',
    weeks: 'Недели 9-10',
    tasks: [
      { title: 'Public API: /booking/public/:clubSlug/* — без JWT, по API-key', layer: 'api' },
      { title: 'Booking Widget (React): встраиваемый компонент (iframe / JS SDK)', layer: 'ui' },
      {
        title: 'Виджет: выбор услуги → тренер → дата → время → данные → оплата → подтверждение',
        layer: 'ui',
      },
      { title: 'Виджет: групповые события (список + бронирование)', layer: 'ui' },
      { title: 'Виджет: недельное расписание (Week Schedule) для фитнес-клубов', layer: 'ui' },
      { title: 'Виджет: кастомизация (цвета, лого, поля) через JSON-конфиг', layer: 'ui' },
      { title: 'Генерация embed-кода (кнопка / iframe / JS)', layer: 'api' },
      { title: 'Anti-fraud: honeypot, rate limit, phone verification', layer: 'api' },
      { title: 'E2E-тесты: полный цикл записи через виджет (Playwright)', layer: 'test' },
    ],
  },
  {
    id: 6,
    name: 'Sprint 6 — Web UI (Админ-панель)',
    weeks: 'Недели 11-12',
    tasks: [
      { title: 'Страница "Услуги": CRUD, категории, drag-and-drop сортировка', layer: 'ui' },
      {
        title: 'Страница "Расписание": журнал записей (week/day view), drag-and-drop',
        layer: 'ui',
      },
      { title: 'Страница "Групповые события": создание, серии, вместимость', layer: 'ui' },
      { title: 'Страница "Записи": таблица, фильтры, статусы, массовые действия', layer: 'ui' },
      { title: 'Страница "Абонементы": типы, выдача клиентам, история', layer: 'ui' },
      { title: 'Страница "Настройки модуля": webhook URL, уведомления, CRM bridge', layer: 'ui' },
      { title: 'Страница "Аналитика": загруженность, конверсия, выручка (графики)', layer: 'ui' },
      { title: 'Интеграция в sidebar web-club-admin + web-platform-admin', layer: 'ui' },
    ],
  },
  {
    id: 7,
    name: 'Sprint 7 — Mobile + Полировка',
    weeks: 'Недели 13-14',
    tasks: [
      {
        title: 'Mobile (тренер): "Моё расписание" — список записей на сегодня/завтра',
        layer: 'ui',
      },
      { title: 'Mobile (тренер): отметка визита (пришёл / не пришёл)', layer: 'ui' },
      { title: 'Mobile (координатор): управление групповыми событиями', layer: 'ui' },
      { title: 'Mobile: push-уведомления о новых записях', layer: 'ui' },
      { title: 'Оптимизация: кэширование availability (Redis), индексы PostgreSQL', layer: 'api' },
      { title: 'Конструктор отчётов: кастомные метрики (агрегация, группировка)', layer: 'api' },
      {
        title: 'Документация: OpenAPI/Swagger, README модуля, руководство интеграции',
        layer: 'docs',
      },
      { title: 'Финальные E2E-тесты: все роли, все сценарии', layer: 'test' },
    ],
  },
];

const prismaModels = `// ═══════════════════════════════════════════════
// BOOKING MODULE — Prisma Schema (автономный)
// ═══════════════════════════════════════════════

enum BookingRecordStatus {
  PENDING
  CONFIRMED
  IN_PROGRESS
  COMPLETED
  CANCELLED
  NO_SHOW
}

enum BookingServiceType {
  INDIVIDUAL
  GROUP
}

enum BookingMembershipKind {
  VISIT_BASED      // фиксированное кол-во визитов
  UNLIMITED        // безлимитный на период
  HOUR_BASED       // по часам
  MIXED            // часть безлимит, часть по визитам
}

model BookingServiceCategory {
  id        String   @id @default(uuid())
  clubId    String?
  name      String
  position  Int      @default(0)
  parentId  String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  club     Club?                    @relation(...)
  parent   BookingServiceCategory?  @relation("CategoryTree", ...)
  children BookingServiceCategory[] @relation("CategoryTree")
  services BookingService[]

  @@index([clubId])
  @@map("booking_service_categories")
}

model BookingService {
  id            String             @id @default(uuid())
  clubId        String?
  categoryId    String?
  name          String
  description   String?
  duration      Int                // минуты
  price         Decimal            @default(0)
  type          BookingServiceType @default(INDIVIDUAL)
  capacity      Int?               // макс. участников (GROUP)
  extraPlaces   Int                @default(0)
  isOnline      Boolean            @default(true)
  membershipOnly Boolean           @default(false)
  color         String?
  position      Int                @default(0)
  isActive      Boolean            @default(true)
  createdAt     DateTime           @default(now())
  updatedAt     DateTime           @updatedAt

  club      Club?                   @relation(...)
  category  BookingServiceCategory? @relation(...)
  staff     BookingServiceStaff[]
  records   BookingRecord[]
  events    BookingGroupEvent[]

  @@index([clubId])
  @@index([categoryId])
  @@map("booking_services")
}

model BookingServiceStaff {
  serviceId String
  staffId   String
  service   BookingService @relation(...)
  staff     User           @relation(...)

  @@id([serviceId, staffId])
  @@map("booking_service_staff")
}

model BookingStaffSchedule {
  id        String   @id @default(uuid())
  clubId    String?
  staffId   String
  dayOfWeek Int      // 0=Пн, 6=Вс
  startTime String   // "09:00"
  endTime   String   // "18:00"
  breakStart String? // "13:00"
  breakEnd  String?  // "14:00"
  isActive  Boolean  @default(true)

  club  Club? @relation(...)
  staff User  @relation(...)

  @@unique([clubId, staffId, dayOfWeek])
  @@index([clubId])
  @@map("booking_staff_schedules")
}

model BookingStaffException {
  id        String   @id @default(uuid())
  clubId    String?
  staffId   String
  date      DateTime @db.Date
  isWorkday Boolean  @default(false)
  startTime String?
  endTime   String?
  reason    String?

  club  Club? @relation(...)
  staff User  @relation(...)

  @@unique([clubId, staffId, date])
  @@map("booking_staff_exceptions")
}

model BookingGroupEvent {
  id          String   @id @default(uuid())
  clubId      String?
  serviceId   String
  staffId     String
  roomId      String?
  title       String?
  startAt     DateTime
  endAt       DateTime
  capacity    Int
  bookedCount Int      @default(0)
  seriesId    String?  // для повторяющихся
  metadata    Json?
  isCancelled Boolean  @default(false)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  club    Club?           @relation(...)
  service BookingService  @relation(...)
  staff   User            @relation(...)
  records BookingRecord[]

  @@index([clubId])
  @@index([startAt])
  @@index([seriesId])
  @@map("booking_group_events")
}

model BookingRecord {
  id            String              @id @default(uuid())
  clubId        String?
  number        Int                 // порядковый номер в рамках клуба
  clientId      String?             // связь с clients (если есть)
  clientName    String
  clientPhone   String
  clientEmail   String?
  serviceId     String
  staffId       String
  groupEventId  String?             // null = индивидуальная
  startAt       DateTime
  endAt         DateTime
  status        BookingRecordStatus @default(PENDING)
  source        String              @default("ADMIN") // ADMIN, WIDGET, API, CRM
  places        Int                 @default(1)
  price         Decimal             @default(0)
  paidAmount    Decimal             @default(0)
  membershipId  String?             // оплата абонементом
  notes         String?
  cancelReason  String?
  confirmedAt   DateTime?
  completedAt   DateTime?
  cancelledAt   DateTime?
  metadata      Json?               // UTM, source details
  createdById   String?
  createdAt     DateTime            @default(now())
  updatedAt     DateTime            @updatedAt

  club       Club?              @relation(...)
  service    BookingService     @relation(...)
  staff      User               @relation(...)
  groupEvent BookingGroupEvent? @relation(...)
  membership BookingClientMembership? @relation(...)
  payments   BookingPayment[]

  // === CRM BRIDGE ===
  crmDealId  String?            // связь с CRM-сделкой (опционально)

  @@index([clubId])
  @@index([staffId, startAt])
  @@index([clientPhone])
  @@index([status])
  @@index([startAt])
  @@index([crmDealId])
  @@map("booking_records")
}

model BookingMembershipType {
  id               String                @id @default(uuid())
  clubId           String?
  name             String
  kind             BookingMembershipKind
  totalVisits      Int?                  // VISIT_BASED
  totalHours       Decimal?              // HOUR_BASED
  validityDays     Int                   // срок действия
  price            Decimal
  serviceIds       String[]              // на какие услуги
  autoActivate     Boolean               @default(true)
  isActive         Boolean               @default(true)
  createdAt        DateTime              @default(now())
  updatedAt        DateTime              @updatedAt

  club        Club?                      @relation(...)
  memberships BookingClientMembership[]

  @@index([clubId])
  @@map("booking_membership_types")
}

model BookingClientMembership {
  id             String   @id @default(uuid())
  clubId         String?
  clientId       String
  typeId         String
  remainingVisits Int?
  remainingHours Decimal?
  activatedAt    DateTime?
  expiresAt      DateTime?
  frozenUntil    DateTime?
  isActive       Boolean  @default(true)
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt

  club    Club?                  @relation(...)
  type    BookingMembershipType  @relation(...)
  records BookingRecord[]

  @@index([clubId])
  @@index([clientId])
  @@map("booking_client_memberships")
}

model BookingPayment {
  id        String   @id @default(uuid())
  clubId    String?
  recordId  String
  amount    Decimal
  method    String   // CARD, SBP, CASH, MEMBERSHIP, DEPOSIT
  status    String   // PENDING, COMPLETED, REFUNDED
  externalId String? // ID платёжной системы
  metadata  Json?
  createdAt DateTime @default(now())

  club   Club?         @relation(...)
  record BookingRecord @relation(...)

  @@index([clubId])
  @@index([recordId])
  @@map("booking_payments")
}

model BookingWaitlist {
  id          String   @id @default(uuid())
  clubId      String?
  clientName  String
  clientPhone String
  serviceId   String
  staffId     String?
  preferredDate DateTime?
  preferredTime String?
  notes       String?
  convertedRecordId String?
  createdAt   DateTime @default(now())

  club Club? @relation(...)

  @@index([clubId])
  @@map("booking_waitlist")
}

model BookingWebhookEndpoint {
  id         String   @id @default(uuid())
  clubId     String?
  url        String
  secret     String   // HMAC signing key
  events     String[] // ["booking.record.created", ...]
  isActive   Boolean  @default(true)
  metadata   Json?
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  club Club?           @relation(...)
  logs BookingWebhookLog[]

  @@index([clubId])
  @@map("booking_webhook_endpoints")
}

model BookingWebhookLog {
  id         String   @id @default(uuid())
  endpointId String
  event      String
  payload    Json
  statusCode Int?
  response   String?
  attempts   Int      @default(1)
  nextRetry  DateTime?
  createdAt  DateTime @default(now())

  endpoint BookingWebhookEndpoint @relation(...)

  @@index([endpointId])
  @@index([createdAt])
  @@map("booking_webhook_logs")
}

// === CRM BRIDGE CONFIG ===
model BookingCrmBridge {
  id              String  @id @default(uuid())
  clubId          String  @unique
  isEnabled       Boolean @default(false)
  pipelineId      String? // в какой pipeline CRM
  newRecordStageId String? // стадия при создании записи
  completedStageId String? // стадия при завершении
  cancelledStageId String? // стадия при отмене
  createDealOnBook Boolean @default(true)
  syncClientData   Boolean @default(true)
  metadata        Json?

  club Club @relation(...)

  @@map("booking_crm_bridges")
}`;

/* ─────────────── components ─────────────── */

function Badge({ children, color }: { children: React.ReactNode; color: string }) {
  return (
    <span
      className="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium"
      style={{ backgroundColor: color + '20', color }}
    >
      {children}
    </span>
  );
}

function MethodBadge({ method }: { method: string }) {
  const colors: Record<string, string> = {
    GET: '#22C55E',
    POST: '#3B82F6',
    PATCH: '#F59E0B',
    PUT: '#8B5CF6',
    DELETE: '#EF4444',
  };
  return <Badge color={colors[method] || '#6B7280'}>{method}</Badge>;
}

function LayerBadge({ layer }: { layer: string }) {
  const map: Record<string, { label: string; color: string }> = {
    schema: { label: 'Schema', color: '#8B5CF6' },
    api: { label: 'API', color: '#3B82F6' },
    test: { label: 'Test', color: '#22C55E' },
    ui: { label: 'UI', color: '#EC4899' },
    docs: { label: 'Docs', color: '#F59E0B' },
  };
  const item = map[layer] || { label: layer, color: '#6B7280' };
  return <Badge color={item.color}>{item.label}</Badge>;
}

function SectionIcon({ icon: Icon, color }: { icon: any; color: string }) {
  return (
    <div
      className="flex h-10 w-10 items-center justify-center rounded-xl"
      style={{ backgroundColor: color + '15' }}
    >
      <Icon className="h-5 w-5" style={{ color }} />
    </div>
  );
}

/* ─────────────── page ─────────────── */

export default function BookingModuleSpecPage() {
  const router = useRouter();
  const printRef = useRef<HTMLDivElement>(null);

  const handlePrint = () => window.print();

  return (
    <div className="min-h-screen bg-gray-50">
      {/* Header */}
      <div className="sticky top-0 z-10 border-b bg-white/80 backdrop-blur-sm print:hidden">
        <div className="mx-auto flex max-w-6xl items-center justify-between px-6 py-3">
          <button
            onClick={() => router.back()}
            className="flex items-center gap-2 text-sm text-gray-500 hover:text-gray-900 transition"
          >
            <ArrowLeft className="h-4 w-4" /> Назад
          </button>
          <div className="flex items-center gap-2">
            <button
              onClick={handlePrint}
              className="flex items-center gap-2 rounded-lg border px-4 py-2 text-sm hover:bg-gray-50 transition"
            >
              <Printer className="h-4 w-4" /> Печать
            </button>
          </div>
        </div>
      </div>

      {/* Content */}
      <div ref={printRef} className="mx-auto max-w-6xl px-6 py-10 print:py-4">
        {/* Title */}
        <div className="mb-10 text-center">
          <div className="mb-4 inline-flex items-center gap-2 rounded-full bg-blue-50 px-4 py-1.5 text-sm font-medium text-blue-700">
            <Calendar className="h-4 w-4" /> Модуль записи клиентов
          </div>
          <h1 className="text-4xl font-bold text-gray-900 mb-3">
            MyFitBooking — Модуль онлайн-записи
          </h1>
          <p className="text-lg text-gray-500 max-w-2xl mx-auto">
            Автономный модуль записи клиентов на тренировки для фитнес-клубов. Аналог YClients с
            глубокой интеграцией в MyFitCRM.
          </p>
          <p className="mt-3 text-sm text-gray-400">Версия 1.0 &middot; {LAST_UPDATE}</p>
        </div>

        {/* Принципы */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={Shield} color="#8B5CF6" />
            Принципы проектирования
          </h2>
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            {[
              {
                title: 'Автономность',
                desc: 'Модуль работает полностью независимо от CRM. Может быть установлен без CRM-модуля. Своя схема данных, свои миграции, свой набор API.',
                icon: Layers,
                color: '#8B5CF6',
              },
              {
                title: 'Опциональная связка с CRM',
                desc: 'Через BookingCrmBridge: при активации записи автоматически создают сделки в CRM pipeline. Настраивается маппинг статусов записи → стадии CRM.',
                icon: Plug,
                color: '#3B82F6',
              },
              {
                title: 'REST события (Webhooks)',
                desc: '17+ типов событий. Каждое действие в модуле генерирует REST webhook с HMAC-подписью. Готовые адаптеры для Bitrix24 и 1С.',
                icon: Webhook,
                color: '#22C55E',
              },
              {
                title: 'Multi-tenancy (RLS)',
                desc: 'Все таблицы содержат clubId. Row-Level Security на уровне PostgreSQL. Полная изоляция данных между клубами.',
                icon: Database,
                color: '#F59E0B',
              },
              {
                title: 'RBAC (6 ролей)',
                desc: 'Trainer видит своё расписание. Manager управляет записями. Club Admin настраивает модуль. Super Admin — полный доступ.',
                icon: Users,
                color: '#EC4899',
              },
              {
                title: 'Модульная лицензия',
                desc: 'Включается через club_modules (moduleId: "booking"). Может иметь лимиты: max_records/month, max_services, max_staff. Metering через usageJson.',
                icon: LayoutGrid,
                color: '#06B6D4',
              },
            ].map((p) => (
              <div key={p.title} className="rounded-xl border bg-white p-5">
                <div className="flex items-center gap-3 mb-2">
                  <p.icon className="h-5 w-5" style={{ color: p.color }} />
                  <h3 className="font-semibold text-gray-900">{p.title}</h3>
                </div>
                <p className="text-sm text-gray-600 leading-relaxed">{p.desc}</p>
              </div>
            ))}
          </div>
        </section>

        {/* Функционал (по YClients) */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-2 flex items-center gap-3">
            <SectionIcon icon={Calendar} color="#3B82F6" />
            Функциональные требования
          </h2>
          <p className="text-sm text-gray-500 mb-6">
            На основе исследования YClients, адаптировано под фитнес-клубы
          </p>

          <div className="space-y-6">
            {coreFeatures.map((f) => (
              <div key={f.title} className="rounded-xl border bg-white overflow-hidden">
                <div className="bg-gray-50 px-5 py-3 border-b">
                  <h3 className="font-semibold text-gray-900">{f.title}</h3>
                </div>
                <ul className="px-5 py-4 space-y-2">
                  {f.items.map((item, i) => (
                    <li key={i} className="flex items-start gap-2 text-sm text-gray-700">
                      <CheckCircle2 className="h-4 w-4 mt-0.5 text-green-500 shrink-0" />
                      {item}
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </section>

        {/* Архитектура */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={Layers} color="#8B5CF6" />
            Архитектура модуля
          </h2>

          <div className="rounded-xl border bg-white p-6 mb-6">
            <h3 className="font-semibold text-gray-900 mb-4">Структура файлов</h3>
            <pre className="text-sm text-gray-700 bg-gray-50 rounded-lg p-4 overflow-x-auto font-mono leading-relaxed">{`apps/api/src/modules/booking/
├── booking.module.ts              # NestJS module registration
├── core/
│   ├── availability.service.ts    # Расчёт свободных слотов
│   ├── booking-permissions.ts     # RBAC: filterByRole, canCreate, canUpdate
│   └── booking-events.service.ts  # EventEmitter2 lifecycle events
├── controllers/
│   ├── services.controller.ts     # CRUD услуг
│   ├── schedule.controller.ts     # Расписание + график тренеров
│   ├── records.controller.ts      # Записи (индивидуальные + групповые)
│   ├── group-events.controller.ts # Групповые события
│   ├── memberships.controller.ts  # Абонементы
│   ├── waitlist.controller.ts     # Лист ожидания
│   ├── webhooks.controller.ts     # Настройка вебхуков
│   ├── analytics.controller.ts    # Отчёты
│   └── public.controller.ts       # Публичный API (виджет)
├── services/
│   ├── booking-services.service.ts
│   ├── staff-schedule.service.ts
│   ├── records.service.ts
│   ├── group-events.service.ts
│   ├── repeat.service.ts          # Повторяющиеся серии
│   ├── memberships.service.ts
│   ├── client-memberships.service.ts
│   ├── payment.service.ts
│   ├── waitlist.service.ts
│   ├── webhook-dispatcher.service.ts
│   ├── crm-bridge.service.ts      # Связь с CRM-модулем
│   ├── notification.service.ts    # Каскадные уведомления
│   └── analytics.service.ts
├── adapters/
│   ├── bitrix24.adapter.ts        # Маппинг событий → Bitrix24
│   └── onec.adapter.ts            # Маппинг событий → 1С
├── processors/
│   ├── webhook.processor.ts       # BullMQ: отправка вебхуков (retry)
│   ├── reminder.processor.ts      # BullMQ: напоминания о визитах
│   └── membership-check.processor.ts # Проверка истекающих абонементов
├── dto/
│   ├── create-service.dto.ts
│   ├── create-record.dto.ts
│   ├── create-group-event.dto.ts
│   ├── create-membership.dto.ts
│   ├── update-record-status.dto.ts
│   ├── book-public.dto.ts
│   └── webhook-settings.dto.ts
└── index.ts`}</pre>
          </div>

          <div className="rounded-xl border bg-white p-6 mb-6">
            <h3 className="font-semibold text-gray-900 mb-4">Связь с CRM (BookingCrmBridge)</h3>
            <pre className="text-sm text-gray-700 bg-gray-50 rounded-lg p-4 overflow-x-auto font-mono leading-relaxed">{`┌─────────────────────┐      EventEmitter2      ┌──────────────────┐
│   Booking Module    │ ──────────────────────→  │   CRM Module     │
│                     │  booking.record.created   │                  │
│  BookingRecord      │  booking.record.completed │  CrmDeal         │
│  BookingGroupEvent  │  booking.record.cancelled │  CrmTimeline     │
│  BookingPayment     │                          │  CrmActivity     │
└─────────────────────┘                          └──────────────────┘
         │                                                │
         │  BookingCrmBridge config:                       │
         │  • pipelineId → в какой pipeline                │
         │  • newRecordStageId → стадия при записи         │
         │  • completedStageId → стадия при визите         │
         │  • cancelledStageId → стадия при отмене         │
         │  • createDealOnBook: true/false                 │
         │  • syncClientData: true/false                   │
         └────────────────────────────────────────────────┘

Webhook Dispatcher (внешние системы):
┌──────────────┐     BullMQ      ┌──────────────┐    HTTP POST    ┌──────────┐
│ EventEmitter │ ──────────────→ │ WebhookQueue │ ──────────────→ │ Bitrix24 │
│              │                 │ (retry x3)   │                 │ 1С       │
│              │                 │ HMAC-sign    │                 │ Custom   │
└──────────────┘                 └──────────────┘                 └──────────┘`}</pre>
          </div>
        </section>

        {/* Prisma Schema */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={Database} color="#F59E0B" />
            Схема данных (Prisma)
          </h2>
          <div className="rounded-xl border bg-white overflow-hidden">
            <div className="bg-gray-50 px-5 py-3 border-b flex items-center justify-between">
              <span className="font-semibold text-gray-900">15 моделей</span>
              <span className="text-xs text-gray-500">prisma/schema.prisma (секция booking)</span>
            </div>
            <pre className="p-5 text-xs text-gray-700 overflow-x-auto font-mono leading-relaxed max-h-[600px] overflow-y-auto">
              {prismaModels}
            </pre>
          </div>
        </section>

        {/* API Endpoints */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={Globe} color="#06B6D4" />
            REST API ({apiEndpoints.length} эндпоинтов)
          </h2>
          <div className="rounded-xl border bg-white overflow-hidden">
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead>
                  <tr className="border-b bg-gray-50">
                    <th className="px-4 py-3 text-left font-medium text-gray-500 w-20">Метод</th>
                    <th className="px-4 py-3 text-left font-medium text-gray-500">Путь</th>
                    <th className="px-4 py-3 text-left font-medium text-gray-500">Описание</th>
                    <th className="px-4 py-3 text-left font-medium text-gray-500 w-32">Доступ</th>
                  </tr>
                </thead>
                <tbody className="divide-y">
                  {apiEndpoints.map((ep, i) => (
                    <tr key={i} className="hover:bg-gray-50 transition">
                      <td className="px-4 py-2.5">
                        <MethodBadge method={ep.method} />
                      </td>
                      <td className="px-4 py-2.5 font-mono text-xs text-gray-700">{ep.path}</td>
                      <td className="px-4 py-2.5 text-gray-600">{ep.desc}</td>
                      <td className="px-4 py-2.5 text-xs text-gray-500">{ep.auth}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </section>

        {/* Webhook Events */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={Webhook} color="#22C55E" />
            REST-события (Webhooks) — {webhookEvents.length} типов
          </h2>
          <div className="rounded-xl border bg-white overflow-hidden mb-4">
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead>
                  <tr className="border-b bg-gray-50">
                    <th className="px-4 py-3 text-left font-medium text-gray-500">Событие</th>
                    <th className="px-4 py-3 text-left font-medium text-gray-500">Триггер</th>
                    <th className="px-4 py-3 text-left font-medium text-gray-500">Payload</th>
                  </tr>
                </thead>
                <tbody className="divide-y">
                  {webhookEvents.map((ev, i) => (
                    <tr key={i} className="hover:bg-gray-50 transition">
                      <td className="px-4 py-2.5 font-mono text-xs text-blue-700 font-medium">
                        {ev.event}
                      </td>
                      <td className="px-4 py-2.5 text-gray-600">{ev.trigger}</td>
                      <td className="px-4 py-2.5 font-mono text-xs text-gray-500">{ev.payload}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
          <div className="rounded-xl border bg-white p-5">
            <h3 className="font-semibold text-gray-900 mb-3">Интеграция с внешними системами</h3>
            <div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
              <div className="rounded-lg bg-orange-50 p-4">
                <h4 className="font-medium text-orange-800 mb-2">Bitrix24</h4>
                <ul className="text-orange-700 space-y-1 text-xs">
                  <li>booking.record.created → crm.deal.add</li>
                  <li>booking.record.completed → crm.deal.update (stage)</li>
                  <li>booking.client.created → crm.contact.add</li>
                  <li>booking.payment.completed → crm.deal.update (sum)</li>
                </ul>
              </div>
              <div className="rounded-lg bg-blue-50 p-4">
                <h4 className="font-medium text-blue-800 mb-2">1С:Фитнес клуб</h4>
                <ul className="text-blue-700 space-y-1 text-xs">
                  <li>booking.record.* → Документ.Запись</li>
                  <li>booking.payment.* → Документ.Оплата</li>
                  <li>booking.membership.* → Документ.Абонемент</li>
                  <li>booking.client.* → Справочник.Клиенты</li>
                </ul>
              </div>
              <div className="rounded-lg bg-gray-100 p-4">
                <h4 className="font-medium text-gray-800 mb-2">Custom (любая система)</h4>
                <ul className="text-gray-700 space-y-1 text-xs">
                  <li>JSON payload + HMAC-SHA256 подпись</li>
                  <li>Retry: 3 попытки (1мин, 5мин, 30мин)</li>
                  <li>Лог всех отправок с ответами</li>
                  <li>Фильтрация по типам событий</li>
                </ul>
              </div>
            </div>
          </div>
        </section>

        {/* Plan */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={Clock} color="#EC4899" />
            План разработки — 7 спринтов (14 недель)
          </h2>
          <div className="space-y-6">
            {sprints.map((s) => (
              <div key={s.id} className="rounded-xl border bg-white overflow-hidden">
                <div className="bg-gray-50 px-5 py-3 border-b flex items-center justify-between">
                  <div>
                    <h3 className="font-semibold text-gray-900">{s.name}</h3>
                    <p className="text-xs text-gray-500">{s.weeks}</p>
                  </div>
                  <span className="text-sm font-medium text-gray-500">{s.tasks.length} задач</span>
                </div>
                <ul className="px-5 py-4 space-y-2">
                  {s.tasks.map((t, i) => (
                    <li key={i} className="flex items-center gap-3 text-sm">
                      <Circle className="h-3.5 w-3.5 text-gray-300 shrink-0" />
                      <span className="text-gray-700 flex-1">{t.title}</span>
                      <LayerBadge layer={t.layer} />
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </section>

        {/* Сравнение с YClients */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={BarChart3} color="#3B82F6" />
            Сравнение: MyFitBooking vs YClients
          </h2>
          <div className="rounded-xl border bg-white overflow-hidden">
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead>
                  <tr className="border-b bg-gray-50">
                    <th className="px-4 py-3 text-left font-medium text-gray-500">Функция</th>
                    <th className="px-4 py-3 text-center font-medium text-gray-500">YClients</th>
                    <th className="px-4 py-3 text-center font-medium text-gray-500">
                      MyFitBooking
                    </th>
                    <th className="px-4 py-3 text-left font-medium text-gray-500">Отличия</th>
                  </tr>
                </thead>
                <tbody className="divide-y">
                  {[
                    {
                      fn: 'Онлайн-запись (индивидуальная)',
                      yc: true,
                      mfb: true,
                      diff: 'Идентично',
                    },
                    { fn: 'Групповые события', yc: true, mfb: true, diff: 'Идентично' },
                    { fn: 'Повторяющиеся события', yc: true, mfb: true, diff: 'Идентично' },
                    {
                      fn: 'Виджет для сайта',
                      yc: true,
                      mfb: true,
                      diff: 'React-based, настраиваемый',
                    },
                    { fn: 'Абонементы', yc: true, mfb: true, diff: 'Идентично' },
                    { fn: 'Онлайн-оплата', yc: true, mfb: true, diff: 'ЮKassa, Т-Банк, СБП' },
                    {
                      fn: 'Лист ожидания',
                      yc: true,
                      mfb: true,
                      diff: 'Авто-уведомление клиента (YClients — нет)',
                    },
                    {
                      fn: 'REST Webhooks',
                      yc: true,
                      mfb: true,
                      diff: 'HMAC-подпись, retry, логирование',
                    },
                    {
                      fn: 'Интеграция Bitrix24',
                      yc: false,
                      mfb: true,
                      diff: 'Готовый адаптер с маппингом',
                    },
                    {
                      fn: 'Интеграция 1С',
                      yc: false,
                      mfb: true,
                      diff: 'Готовый адаптер (XML/JSON)',
                    },
                    {
                      fn: 'Связь с CRM (pipeline)',
                      yc: false,
                      mfb: true,
                      diff: 'BookingCrmBridge — уникальная фича',
                    },
                    {
                      fn: 'Multi-tenancy (RLS)',
                      yc: false,
                      mfb: true,
                      diff: 'Полная изоляция данных',
                    },
                    {
                      fn: 'Модульная система',
                      yc: false,
                      mfb: true,
                      diff: 'Включение/выключение per club',
                    },
                    {
                      fn: 'RBAC (6 ролей)',
                      yc: true,
                      mfb: true,
                      diff: 'Глубже: filterByRole в API',
                    },
                    { fn: 'Каскадные уведомления', yc: true, mfb: true, diff: '+ Telegram канал' },
                    {
                      fn: 'Конструктор отчётов',
                      yc: true,
                      mfb: false,
                      diff: 'MVP: стандартные отчёты, конструктор — v2',
                    },
                  ].map((row, i) => (
                    <tr key={i} className="hover:bg-gray-50 transition">
                      <td className="px-4 py-2.5 font-medium text-gray-700">{row.fn}</td>
                      <td className="px-4 py-2.5 text-center">
                        {row.yc ? (
                          <CheckCircle2 className="h-4 w-4 text-green-500 mx-auto" />
                        ) : (
                          <Circle className="h-4 w-4 text-gray-300 mx-auto" />
                        )}
                      </td>
                      <td className="px-4 py-2.5 text-center">
                        {row.mfb ? (
                          <CheckCircle2 className="h-4 w-4 text-green-500 mx-auto" />
                        ) : (
                          <Circle className="h-4 w-4 text-gray-300 mx-auto" />
                        )}
                      </td>
                      <td className="px-4 py-2.5 text-xs text-gray-500">{row.diff}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </section>

        {/* Definition of Done */}
        <section className="mb-12">
          <h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center gap-3">
            <SectionIcon icon={CheckCircle2} color="#22C55E" />
            Definition of Done
          </h2>
          <div className="rounded-xl border bg-white p-6">
            <ul className="space-y-3">
              {[
                'Все 38+ API эндпоинтов реализованы с Swagger-документацией',
                'RBAC: каждый эндпоинт защищён @Roles(), permissions filterByRole',
                'Multi-tenancy: clubId + RLS во всех таблицах',
                'Модуль активируется через @RequireModule("booking")',
                'CRM Bridge: записи создают сделки в CRM pipeline (опционально)',
                'Webhooks: 17 типов событий с HMAC-подписью и retry',
                'Адаптеры: Bitrix24 + 1С (маппинг событий)',
                'Виджет: встраиваемый React-компонент (iframe / JS SDK)',
                'Абонементы: 4 типа, автосписание, заморозка',
                'Уведомления: каскадная доставка (Push → Email → TG → SMS)',
                'Unit-тесты: >= 70% покрытие бизнес-логики',
                'E2E-тесты: полный цикл записи (все роли, все сценарии)',
                'typecheck проходит для api, web-club-admin, web-platform-admin',
                'Существующие тесты MyFitCRM не ломаются',
                'Разработка в отдельной ветке, не блокирует основную разработку',
              ].map((item, i) => (
                <li key={i} className="flex items-start gap-3 text-sm text-gray-700">
                  <CheckCircle2 className="h-4 w-4 mt-0.5 text-green-500 shrink-0" />
                  {item}
                </li>
              ))}
            </ul>
          </div>
        </section>

        {/* Footer */}
        <div className="text-center text-sm text-gray-400 pb-8 print:pb-2">
          MyFitCRM &middot; MyFitBooking Module Specification &middot; {LAST_UPDATE}
        </div>
      </div>
    </div>
  );
}
