import { useState, ReactNode } from 'react';
import { Input } from '@/components/ui/input';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from '@/components/ui/accordion';
import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogContent,
} from '@/components/ui/dialog';
import {
  Search, BookOpen, ShoppingCart, Building2, Users, GraduationCap, MapPin,
  Tag, Shield, CalendarDays, Monitor, ClipboardList, FileText, Download,
  ZoomIn, Play, Compass, KeyRound, Network, Workflow,
} from 'lucide-react';
import TutorialOverlay, { tutorialStepMap } from '@/components/admin/TutorialOverlay';
import type { AppRole } from '@/contexts/RolePreviewContext';
import { HIDDEN_GROUPS } from '@/lib/page-visibility';

import ordersImg from '@/assets/sop/orders.png';
import companiesImg from '@/assets/sop/companies.png';
import trainersImg from '@/assets/sop/trainers.png';
import coursesImg from '@/assets/sop/courses.png';
import venuesImg from '@/assets/sop/venues.png';
import discountCodesImg from '@/assets/sop/discount-codes.png';
import userRolesImg from '@/assets/sop/user-roles.png';
import calendarImg from '@/assets/sop/calendar.png';
import availabilityImg from '@/assets/sop/availability.png';

// Canonical role keys (matches the DB role names + RolePreviewContext.AppRole).
export type RoleKey = AppRole;

const ALL_STAFF: RoleKey[] = ['sys_admin', 'sys_manager', 'admin', 'manager'];
const EVERYONE: RoleKey[] = [...ALL_STAFF, 'company_manager', 'company_trainer', 'delegate'];

const ROLE_LABELS: Record<RoleKey, string> = {
  sys_admin: 'System Admin',
  sys_manager: 'System Manager',
  admin: 'Admin',
  manager: 'Manager',
  company_manager: 'Company Manager',
  company_trainer: 'Company Trainer',
  delegate: 'Delegate',
};

// Collapse the four staff roles into a single "Staff" badge to keep the chips
// readable; show "Everyone" when a section applies to every role.
const roleBadges = (roles: RoleKey[]): string[] => {
  if (EVERYONE.every((r) => roles.includes(r))) return ['Everyone'];
  const out: string[] = [];
  if (ALL_STAFF.every((r) => roles.includes(r))) out.push('Staff');
  else ALL_STAFF.filter((r) => roles.includes(r)).forEach((r) => out.push(ROLE_LABELS[r]));
  (['company_manager', 'company_trainer', 'delegate'] as RoleKey[])
    .filter((r) => roles.includes(r))
    .forEach((r) => out.push(ROLE_LABELS[r]));
  return out;
};

type SOPProcedure = {
  id: string;
  title: string;
  roles: RoleKey[];
  // A procedure is either step-based (numbered how-to) or prose (reference).
  steps?: string[];
  body?: string[];
  notes?: string[];
};

type SOPCategory = {
  id: string;
  title: string;
  icon: React.ElementType;
  description: string;
  roles: RoleKey[];
  // When set and present in HIDDEN_GROUPS, the whole category is hidden from
  // the manual for everyone — mirroring a hidden sidebar group.
  group?: string;
  screenshot?: string;
  procedures: SOPProcedure[];
};

// Internal-only SOP sections — hidden from the manual UI (only the team needs
// these). The data is left intact so search/links keep working internally.
const HIDDEN_SOP_CATEGORY_IDS = new Set(['overview', 'pages', 'processes']);

const sopCategories: SOPCategory[] = [
  // ── Reference: how the whole thing fits together ──────────────────────────
  {
    id: 'overview',
    title: 'System Overview',
    icon: Compass,
    description: 'What the platform is, how a booking flows end to end, and the words we use.',
    roles: EVERYONE,
    procedures: [
      {
        id: 'what-is-utc',
        title: 'What this platform is',
        roles: EVERYONE,
        body: [
          'Utility Training Centre (UTC) is a training-course booking and management platform. The public website lets customers browse and book NRSWA, SMART Awards and general utility courses; behind the login sits an admin area for staff plus self-service portals for companies, trainers and delegates.',
          'It is multi-tenant / white-label: a training company can be given its own branded portal on a subdomain, with its own courses, content and (optionally) its own Stripe account. The "Locktel" pages are one such sub-tenant.',
          'There are three broad surfaces: (1) the public marketplace (no login), (2) the /admin area (staff, plus the specific pages granted to portal roles), and (3) the role-specific self-service portal each user is given after signing in.',
        ],
      },
      {
        id: 'booking-lifecycle',
        title: 'The booking lifecycle (big picture)',
        roles: EVERYONE,
        body: [
          '1. A customer (or a logged-in company) books a course for one or more delegates and pays by card, on company credit, or against an invoice.',
          '2. The order is created. A confirmation email + PDF invoice is sent, and each delegate is emailed a TD-02 pre-course questionnaire.',
          '3. Staff assign a trainer and venue/rooms and move the booking to Confirmed. Joining instructions go out automatically (24h after booking, or immediately if the course is within 48h).',
          '4. On the day, delegates check in via a QR code and complete the TD-07 induction and TD-29 health & safety forms with the instructor.',
          '5. After the course, certificates are issued and tracked for expiry; refunds / credit notes are handled if needed.',
        ],
      },
      {
        id: 'glossary',
        title: 'Key terms (glossary)',
        roles: EVERYONE,
        body: [
          'Course — a training product (title, price, duration in days, capacity, category).',
          'Course date / session — a scheduled run of a course on specific dates, at a venue, with a trainer.',
          'Order — a booking of a course for one or more delegates. Money is stored in pence, ex-VAT and net of discount; VAT is added only when displaying or charging.',
          'Delegate — a person attending a course. May also have a delegate login.',
          'Trainer — an instructor who can be assigned to courses; has a weekly availability pattern plus date overrides.',
          'Venue — a training location with rooms and yards used for resource scheduling.',
          'Training company — a customer or training-provider organisation. Can have a credit account, branding, services and managers/trainers.',
          'Credit — pre-agreed spend a company can book against. Reserved on booking, restored on refund.',
          'Certificate — proof of completed training with issue/expiry dates; powers the compliance matrix and skills-gap.',
        ],
      },
      {
        id: 'navigating',
        title: 'Where everything lives',
        roles: EVERYONE,
        body: [
          'Public site — the main domain (home, /courses, /course/{slug}, /cart, checkout, /e-learning, /about, /contact, etc.). No login needed.',
          'Admin area — /admin/*. Staff see the full sidebar; company managers, trainers and delegates can reach the specific /admin pages granted to them.',
          'Portals — after signing in, each non-staff role gets its own self-service home, scoped to that user.',
          'This manual — /admin/sops. Everyone with a login can open it and sees only the sections relevant to their role. System Admins see everything and can preview any role with the "Viewing as" switch at the top.',
        ],
      },
    ],
  },
  {
    id: 'roles',
    title: 'Roles & Permissions',
    icon: KeyRound,
    description: 'The roles, what each can do, company scoping, and how access is granted.',
    // Role/access administration is only for staff who manage it (User Roles /
    // Role Management). Portal roles don't configure roles, so they don't see this.
    roles: ['sys_admin', 'admin'],
    procedures: [
      {
        id: 'role-directory',
        title: 'The roles, explained',
        roles: EVERYONE,
        body: [
          'System Admin — full access to everything, including Role Management, Services and audit logs. The bootstrap role; can never be locked out. Signs in with two-factor (OTP).',
          'System Manager — system-wide operational access (orders, calendar, courses, companies, finance, audit) but cannot manage roles or Services.',
          'Admin (legacy) — broad staff access including User Roles; cannot reach Role Management or Services.',
          'Manager (legacy) — day-to-day operations (orders, courses, venues, trainers, certificates, etc.); no access to User Roles, Services or audit logs.',
          "Company Manager — self-service manager of ONE training company. Sees only their company's orders, delegates, certificates, finance and compliance tools, and approves their delegates' booking requests. Lands on the Company Portal.",
          'Company Trainer — a training provider / instructor. Sees their own schedule and assigned courses and runs on-the-day check-in. Lands on the Provider Portal.',
          'Delegate — a learner. Sees their own courses, certificates, e-learning and onboarding forms. Lands on the Delegate Dashboard.',
          'User — a basic account with no admin access (e.g. a customer who only buys courses).',
        ],
      },
      {
        id: 'how-access-works',
        title: 'How access is controlled',
        roles: [...ALL_STAFF],
        body: [
          'Each screen is a "page" record listing the routes it covers. A role→page grid (managed at Role Management, System Admin only) decides which roles can open which pages, and the "page" middleware enforces it on every request.',
          'The whole /admin area also requires admin access — staff, company managers, company trainers and delegates pass; plain users do not.',
          'System Admin bypasses the grid (always allowed), so it can never be locked out of Role Management.',
          'What you see in the sidebar is exactly the set of pages your role(s) are granted — nothing more.',
        ],
      },
      {
        id: 'role-scoping',
        title: 'Company scoping',
        roles: [...ALL_STAFF, 'company_manager', 'company_trainer'],
        body: [
          "Company Managers and Company Trainers are tied to a specific training company (stored on their role row).",
          "Their pages and API calls are filtered to that company only — a company manager can only see and act on their own company's orders, delegates, certificates and finance.",
          'System-level staff are not scoped and can act across all companies.',
        ],
      },
      {
        id: 'getting-a-role',
        title: 'How users get a role & sign in',
        roles: EVERYONE,
        body: [
          "Staff assign roles at User Roles (or invite new users). If the person doesn't have an account yet, the role is stored as a pending assignment and applied automatically the first time they log in.",
          'Invites are sent by email with a link to set up the account; company-scoped roles also capture which company the user belongs to.',
          'System-level staff must complete two-factor authentication (a 6-digit code emailed on login) unless they are on a trusted device (remembered for 6 hours).',
          'Forgotten passwords are reset from the login page via an emailed reset link.',
        ],
      },
    ],
  },
  {
    id: 'pages',
    title: 'Pages & Links Reference',
    icon: Network,
    description: 'The screens you can open and what each is for.',
    roles: EVERYONE,
    // Generated per-viewer in the component from PAGE_REFERENCE, so the list
    // only ever shows pages the current role can actually open.
    procedures: [],
  },
  {
    id: 'processes',
    title: 'Processes — How It Connects',
    icon: Workflow,
    description: 'The end-to-end workflows and how the pieces fit together.',
    roles: EVERYONE,
    procedures: [
      {
        id: 'proc-booking',
        title: 'Booking & checkout',
        roles: EVERYONE,
        body: [
          'On the public site a customer picks a course, the number of delegates and a start date, enters billing + per-delegate details, optionally applies a discount code, and pays.',
          'Payment options: Card (Stripe payment intent), Company Credit (drawn from the company credit balance), or Invoice (pay later on account).',
          'Completing checkout creates the order(s), stores the price in pence ex-VAT and net of discount, sends the confirmation email + PDF invoice, and emails each delegate the TD-02 pre-course form.',
        ],
      },
      {
        id: 'proc-payments',
        title: 'Payment methods & money rules',
        roles: [...ALL_STAFF, 'company_manager'],
        body: [
          'Card — handled by Stripe; refunds are pushed back to Stripe automatically.',
          'Company credit — the gross (incl-VAT) cost is reserved against the company available credit at booking and restored on refund.',
          'Invoice — the order is confirmed and billed; finance tracks the outstanding invoice.',
          'All money columns are stored ex-VAT and already net of any discount; VAT (20%) is added only when displaying or charging. The stored discount figure is informational — the stored price is already the post-discount amount.',
        ],
      },
      {
        id: 'proc-booking-requests',
        title: 'Booking requests & approval',
        roles: [...ALL_STAFF, 'company_manager', 'delegate'],
        body: [
          "A delegate (or company user) submits a booking request from the portal; the company's managers are notified in-app and by email.",
          'A Company Manager (or staff) approves it on Course Requests: this creates a confirmed, invoice-method order, reserves the gross cost against company credit, adds the delegate and provisions the booking.',
          'Approval is the single point where credit is reserved — there is no second checkout. If the company has no credit account or insufficient balance, approval is blocked.',
          "Rejecting notifies the delegate. Company managers can only act on their own company's requests.",
        ],
      },
      {
        id: 'proc-credit-finance',
        title: 'Company credit & finance',
        roles: [...ALL_STAFF, 'company_manager'],
        body: [
          'Each training company can have a credit limit and an available-credit balance. Bookings on credit decrement it; refunds and credit notes restore or extend it.',
          'Finance shows outstanding invoices and an overview; company managers see only their own figures.',
        ],
      },
      {
        id: 'proc-refunds',
        title: 'Refunds, cancellations & credit notes',
        roles: [...ALL_STAFF],
        body: [
          'Refund an order from its row: enter an amount (partial or full) and a reason. Card refunds go back through Stripe; credit-paid orders return the credit to the company.',
          'Cancelling sets the order to Cancelled but does not auto-refund — process a refund separately if needed.',
          'Refunds can generate credit notes (store credit) that can be spent on future bookings.',
        ],
      },
      {
        id: 'proc-discounts',
        title: 'Discounts & coupons',
        roles: [...ALL_STAFF, 'company_manager'],
        body: [
          'Discount codes can be percentage or fixed-amount, scoped to everyone, a single company, or a single user, with optional max-uses and validity dates.',
          'At checkout the code is validated and applied before payment; the stored order price is already net of the discount.',
        ],
      },
      {
        id: 'proc-certs',
        title: 'Certificates & compliance',
        roles: [...ALL_STAFF, 'company_manager', 'delegate'],
        body: [
          'Certificates are issued against a delegate + course with issue/expiry dates and an uploaded file; status is colour-coded valid / expiring / expired.',
          "The company compliance matrix and Skills Gap cross-reference delegates' certificates against the courses their job role requires, highlighting gaps to book.",
          'Delegates see their own certificates in the Certificate Wallet on their dashboard.',
        ],
      },
      {
        id: 'proc-onboarding',
        title: 'Delegate onboarding (TD-02 / TD-07 / TD-29)',
        roles: [...ALL_STAFF, 'company_trainer', 'delegate'],
        body: [
          'The TD-02 pre-course questionnaire is emailed to each delegate when the order completes (adjustments, medical, allergies, emergency contact). The assigned trainer is notified on submission.',
          'On the day, a QR code on the order opens the delegate onboarding portal; delegates verify by email OTP and complete TD-07 (induction) and TD-29 (health & safety), signed with the instructor.',
          "Submitted forms appear on the order's Onboarding tab and on the calendar.",
        ],
      },
      {
        id: 'proc-elearning',
        title: 'E-learning',
        roles: [...ALL_STAFF, 'delegate'],
        body: [
          'E-learning courses are hosted on VideoTile. Enrolled delegates launch a course from their dashboard via a one-click link that signs them into the LMS.',
          'Staff manage the e-learning catalogue and enrolments under Training › E-Learning.',
        ],
      },
      {
        id: 'proc-scheduling',
        title: 'Trainers, availability, date-changes & waitlist',
        roles: [...ALL_STAFF, 'company_trainer'],
        body: [
          'Trainers have a weekly availability pattern plus date overrides; bank holidays are excluded. Assignments link trainers (and default venues) to courses.',
          'Venue rooms/yards are scheduled per course day to prevent double-booking; Location Overrides can block resources.',
          'Customers/companies can request a date change on a booking; staff (or company trainers for their courses) approve or reject it. When a full course frees a space, notify the waitlist.',
        ],
      },
      {
        id: 'proc-invites-auth',
        title: 'Invites, roles & sign-in',
        roles: [...ALL_STAFF],
        body: [
          'Invite a user (email + role + optional company) from User Roles; a pending assignment is created and applied on first login.',
          'Roles are assigned/removed on the same page; Role Management (System Admin) controls which roles can open which pages.',
          'System staff sign in with email/password plus an emailed OTP; trusted devices skip OTP for 6 hours.',
        ],
      },
      {
        id: 'proc-white-label',
        title: 'White-label / tenant portals',
        roles: [...ALL_STAFF],
        body: [
          'A training company can be given branding (subdomain, logo, colours, hero, contact details) to run a branded portal, with its own featured courses, blog/news and testimonials.',
          "Payments on a tenant subdomain can use the company's own Stripe account (keys set on the company's branding / Stripe config).",
          'The Locktel pages and Locktel CMS are an example of a managed tenant.',
        ],
      },
      {
        id: 'proc-import',
        title: 'Old-site data import',
        roles: [...ALL_STAFF],
        body: [
          'A console command (import:oldsite) migrates the legacy database into the new schema, splitting old multi-item orders into one order per line item and apportioning whole-cart discounts across the lines.',
          'This is a maintenance / data task run from the server, not a screen in the app.',
        ],
      },
    ],
  },

  // ── Step-by-step procedures ───────────────────────────────────────────────
  {
    id: 'orders',
    title: 'Orders & Bookings',
    icon: ShoppingCart,
    description: 'Managing course bookings, payments, refunds, and order lifecycle.',
    roles: EVERYONE,
    screenshot: ordersImg,
    procedures: [
      {
        id: 'view-orders',
        title: 'Viewing & Filtering Orders',
        roles: [...ALL_STAFF, 'company_manager', 'delegate'],
        steps: [
          'Navigate to Orders from the sidebar menu.',
          'Use the search bar to filter by customer name, email, or order ID.',
          'Use the status filter dropdown to show only Pending, Paid, Confirmed, Cancelled, or Refunded orders.',
          'Click the expand arrow on any order row to view full details including delegates, venue, and trainer.',
          'Company Managers will only see orders belonging to their company.',
        ],
      },
      {
        id: 'assign-trainer-venue',
        title: 'Assigning Trainers & Venues to Orders',
        roles: [...ALL_STAFF],
        steps: [
          'Expand the order by clicking the row.',
          'In the Trainer field, select a trainer from the dropdown. Only trainers assigned to the course will appear.',
          'In the Venue field, select a venue from the dropdown.',
          "Click 'Save Changes' to update the order.",
          "Once both trainer and venue are assigned, the order status can be moved to 'Confirmed'.",
        ],
      },
      {
        id: 'process-refund',
        title: 'Processing a Refund',
        roles: [...ALL_STAFF],
        steps: [
          "Expand the order and click the 'Refund' button.",
          'Enter the refund amount in pounds (partial or full refund supported).',
          'Provide a reason for the refund.',
          "Click 'Process Refund' to submit.",
          'For Stripe payments, the refund is processed automatically. For credit payments, the credit is returned to the company account.',
          "The order status will update to 'Refunded' and the refund details will appear in the order.",
        ],
      },
      {
        id: 'cancel-order',
        title: 'Cancelling an Order',
        roles: [...ALL_STAFF],
        steps: [
          "Expand the order and click the 'Cancel' button.",
          'Confirm the cancellation in the dialog.',
          "The order status will change to 'Cancelled' and a timestamp will be recorded.",
          'Note: Cancellation does not automatically process a refund. Process a refund separately if required.',
        ],
      },
      {
        id: 'resend-emails',
        title: 'Resending Order Emails',
        roles: [...ALL_STAFF],
        steps: [
          'Expand the order to view the full details.',
          "Click 'Resend Confirmation' to re-send the booking confirmation email.",
          "Click 'Resend Pre-Course Form' to re-issue the TD-02 questionnaire to all delegates.",
          "Click 'Send Joining Instructions' to manually trigger joining instruction emails.",
          'All emails are sent to the billing email address and/or delegate email addresses as appropriate.',
        ],
      },
      {
        id: 'qr-code',
        title: 'Generating QR Codes for On-Site Check-In',
        roles: [...ALL_STAFF, 'company_trainer'],
        steps: [
          "Expand the order and click the 'QR Code' button.",
          'A QR code will be generated that links to the delegate onboarding portal.',
          'Print or display the QR code at the training venue.',
          'Delegates scan the code with their phone to access the onboarding forms.',
        ],
      },
    ],
  },
  {
    id: 'companies',
    title: 'Company Management',
    icon: Building2,
    description: 'Creating and managing training company accounts, credit, and branding.',
    roles: [...ALL_STAFF],
    screenshot: companiesImg,
    procedures: [
      {
        id: 'create-company',
        title: 'Creating a New Company',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Companies from the sidebar.',
          "Click 'Add Company' button.",
          'Fill in the company details: Name, Registration Number, VAT Number, Contact Phone, Contact Email, and Address.',
          'Set the Account Admin Name and Accounts Contact details for invoicing.',
          "Select the Company Type: 'Training Company' (can have trainers and venues) or 'Purchasing Company' (books courses only).",
          'Set Payment Terms (default 30 days) and Credit Limit.',
          "Click 'Save' to create the company.",
        ],
      },
      {
        id: 'manage-credit',
        title: 'Managing Company Credit',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Companies and click on the company name to view details.',
          "Go to the 'Credit' tab.",
          'View current credit limit and available credit.',
          'Adjust the credit limit as needed — this controls how much the company can book on account.',
          "Credit is automatically deducted when orders are placed using 'Company Credit' payment method.",
          'Credit is restored when orders are refunded.',
        ],
      },
      {
        id: 'company-branding',
        title: 'Setting Up Company Branding (White Label)',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to the company detail page.',
          "Go to the 'Branding' tab (only visible for Training Companies).",
          'Upload the company logo and set primary/secondary brand colours.',
          "Configure the subdomain for the company's white-label portal.",
          'Set a hero image or video for the homepage.',
          "Set contact information that appears on the company's public-facing pages.",
          "Toggle 'Active' to enable the branded portal.",
          'Use the preview link to verify the branding on the live site.',
        ],
      },
      {
        id: 'assign-company-manager',
        title: 'Assigning a Company Manager',
        roles: ['sys_admin', 'admin'],
        steps: [
          'Navigate to User Roles from the sidebar.',
          "In the 'Invite New User' section, enter the person's email and full name.",
          "Select the role 'Company Manager'.",
          'Select the company to link them to from the company dropdown.',
          "Click 'Send Invite'.",
          'The invited user will receive an email to set up their account.',
          'Once registered, they will only see data relevant to their assigned company.',
        ],
      },
    ],
  },
  {
    id: 'trainers',
    title: 'Trainer Management',
    icon: Users,
    description: 'Adding trainers, managing availability, and linking to companies.',
    roles: [...ALL_STAFF, 'company_trainer'],
    screenshot: trainersImg,
    procedures: [
      {
        id: 'add-trainer',
        title: 'Adding a New Trainer',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Trainers from the sidebar.',
          "Click 'Add Trainer'.",
          "Enter the trainer's First Name, Last Name, Email, Phone, and any Notes.",
          "Click 'Save' to create the trainer record.",
        ],
      },
      {
        id: 'link-trainer-company',
        title: 'Linking a Trainer to a Company',
        roles: [...ALL_STAFF],
        steps: [
          'On the Trainers page, find the trainer and click the Building icon.',
          'In the dialog, select the company from the dropdown.',
          "Click 'Link' to associate the trainer with that company.",
          'A trainer can be linked to multiple companies.',
          "Linked trainers appear in the company's trainer list and can be assigned to that company's courses.",
        ],
      },
      {
        id: 'manage-availability',
        title: 'Managing Trainer Availability',
        roles: [...ALL_STAFF, 'company_trainer'],
        steps: [
          'Navigate to Availability from the sidebar, or click the Calendar icon next to a trainer.',
          'The weekly availability grid shows which days the trainer is available (Mon–Fri).',
          'Toggle days on/off to set the default weekly pattern.',
          "To override specific dates (e.g., holidays), click 'Add Override'.",
          'Select the date, set availability to Yes/No, and optionally add a reason.',
          'Overrides take priority over the weekly pattern.',
          'Bank holidays are automatically excluded from availability.',
        ],
      },
    ],
  },
  {
    id: 'courses',
    title: 'Course Management',
    icon: GraduationCap,
    description: 'Creating, editing, and managing training courses and e-learning.',
    roles: [...ALL_STAFF],
    screenshot: coursesImg,
    procedures: [
      {
        id: 'create-course',
        title: 'Creating a New Course',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Courses from the sidebar.',
          "Click 'Add Course'.",
          'Fill in the course details: Title, Category (NRSWA/Smart Awards/General), Slug (URL-friendly name).',
          'Set the Price, Original Price (for showing discounts), Duration in Days, and Capacity.',
          'Add a Description, Course Content, Certification details, and Who Attends information.',
          'Specify PPE Requirements, Facilities, and Location details.',
          'Upload a course image.',
          "Toggle 'Featured' to show the course on the homepage.",
          "Toggle 'Active' to make the course available for booking.",
          "Click 'Save' to create the course.",
        ],
      },
      {
        id: 'assign-trainers-course',
        title: 'Assigning Trainers to Courses',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Course Assignments from the sidebar.',
          'Select a course from the dropdown.',
          'Select a trainer and optionally a default venue.',
          "Click 'Assign' to link the trainer to the course.",
          'Only assigned trainers will appear as options when booking orders for that course.',
        ],
      },
      {
        id: 'venue-schedules',
        title: 'Setting Up Venue/Room Schedules for Courses',
        roles: [...ALL_STAFF],
        steps: [
          'When editing a course, scroll to the Venue Schedule Grid section.',
          'For each day of the course, specify which venue rooms and yards are needed.',
          'Select the session (AM/PM/Full Day) for each resource.',
          'This schedule determines resource availability and prevents double-booking.',
        ],
      },
      {
        id: 'manage-elearning',
        title: 'Managing E-Learning Courses',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to E-Learning from the sidebar.',
          'E-Learning courses are managed separately from classroom courses.',
          'Add courses with external links, pricing, and descriptions.',
          'E-Learning courses appear in a dedicated section on the public website.',
        ],
      },
    ],
  },
  {
    id: 'venues',
    title: 'Venue Management',
    icon: MapPin,
    description: 'Managing training venues, rooms, and yards.',
    roles: [...ALL_STAFF],
    screenshot: venuesImg,
    procedures: [
      {
        id: 'create-venue',
        title: 'Creating a New Venue',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Venues from the sidebar.',
          "Click 'Add Venue'.",
          'Enter the venue Name, Address, City, Postcode, Country, and Capacity.',
          'Optionally link the venue to a company.',
          "Set the status to 'Active'.",
          "Click 'Save'.",
        ],
      },
      {
        id: 'manage-rooms-yards',
        title: 'Managing Rooms & Yards',
        roles: [...ALL_STAFF],
        steps: [
          'On the Venues page, click the Room or Yard icon next to a venue.',
          "Click 'Add Room' or 'Add Yard'.",
          'Enter the name, capacity, and status.',
          'Rooms and yards can be used in course venue schedules for resource allocation.',
          'Inactive rooms/yards will not appear as booking options.',
        ],
      },
    ],
  },
  {
    id: 'discount-codes',
    title: 'Discount Codes',
    icon: Tag,
    description: 'Creating and managing promotional and company-specific discount codes.',
    roles: [...ALL_STAFF],
    screenshot: discountCodesImg,
    procedures: [
      {
        id: 'create-discount',
        title: 'Creating a Discount Code',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Discount Codes from the sidebar.',
          "Click 'Add Discount Code'.",
          'Enter the code (e.g., SAVE20, COMPANY50).',
          'Choose Discount Type: Percentage (%) or Fixed Amount (£).',
          'Enter the discount value (percentage or amount in pounds).',
          'Select the Scope: General (anyone can use), Company (linked to specific company), or User (linked to specific user email).',
          'If Company or User scope, select/enter the relevant company or user.',
          'Set Max Uses (leave blank for unlimited).',
          'Set validity dates (optional — From and Until).',
          'Toggle Active on/off.',
          "Click 'Save'.",
        ],
      },
      {
        id: 'monitor-usage',
        title: 'Monitoring Discount Code Usage',
        roles: [...ALL_STAFF],
        steps: [
          "The Discount Codes table shows 'Times Used' for each code.",
          "Compare against 'Max Uses' to see remaining availability.",
          'Inactive codes are shown with a greyed-out badge.',
          "Expired codes (past the 'Valid Until' date) will no longer be accepted at checkout.",
        ],
      },
    ],
  },
  {
    id: 'user-roles',
    title: 'User & Role Management',
    icon: Shield,
    description: 'Managing user accounts, role assignments, and invitations.',
    roles: ['sys_admin', 'admin'],
    screenshot: userRolesImg,
    procedures: [
      {
        id: 'assign-role',
        title: 'Assigning a Role to an Existing User',
        roles: ['sys_admin', 'admin'],
        steps: [
          'Navigate to User Roles from the sidebar.',
          "In the 'Assign Role' section, enter the user's email address.",
          'Select the role from the dropdown.',
          'If the role is company-scoped (Company Manager or Company Trainer), select the company.',
          "Click 'Assign Role'.",
          'The user will immediately have access to the relevant admin features.',
        ],
      },
      {
        id: 'invite-user',
        title: 'Inviting a New User',
        roles: ['sys_admin', 'admin'],
        steps: [
          "Go to the 'Invite New User' tab.",
          "Enter the new user's email address and full name.",
          'Select the role they should have.',
          'If company-scoped, select the company.',
          "Click 'Send Invite'.",
          'An invitation email is sent. The user clicks the link to create their account.',
          'Upon registration, the assigned role is automatically applied.',
        ],
        notes: [
          "Pending invitations appear in the 'Pending Invitations' tab until the user registers.",
          "You can delete a pending invitation if it's no longer needed.",
        ],
      },
      {
        id: 'remove-role',
        title: "Removing a User's Role",
        roles: ['sys_admin', 'admin'],
        steps: [
          'Find the user in the roles table.',
          'Click the delete (trash) icon next to the role you want to remove.',
          'Confirm the deletion.',
          'The user will immediately lose access to the corresponding admin features.',
        ],
      },
    ],
  },
  {
    id: 'calendar',
    title: 'Training Calendar',
    icon: CalendarDays,
    description: 'Viewing and managing the training schedule.',
    roles: [...ALL_STAFF],
    screenshot: calendarImg,
    procedures: [
      {
        id: 'view-calendar',
        title: 'Using the Training Calendar',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Training Calendar from the sidebar.',
          'The calendar displays all confirmed course bookings by date.',
          'Use the month/week toggle to change the view.',
          'Click on a booking to see details including course, trainer, venue, and delegates.',
          'Company Managers and Company Trainers see the equivalent schedule, scoped to them, in their own portals.',
        ],
      },
    ],
  },
  {
    id: 'onboarding',
    title: 'Delegate Onboarding',
    icon: ClipboardList,
    description: 'Digital onboarding forms, pre-course questionnaires, and on-the-day check-in.',
    roles: [...ALL_STAFF, 'company_trainer'],
    procedures: [
      {
        id: 'pre-course-form',
        title: 'Pre-Course Questionnaire (TD-02)',
        roles: [...ALL_STAFF],
        steps: [
          'The TD-02 form is automatically sent to all delegates when a course booking is completed.',
          'Each delegate receives a unique link to their email address.',
          'The form collects: adjustment/accessibility needs, medical conditions, medication, allergies, and emergency contact details.',
          'Once submitted, the trainer assigned to the course is notified by email.',
          "If the form hasn't been sent, use the 'Resend Pre-Course Form' button on the order.",
        ],
      },
      {
        id: 'on-day-checkin',
        title: 'On-the-Day Check-In Process',
        roles: [...ALL_STAFF, 'company_trainer'],
        steps: [
          'Generate a QR code from the order page and display it at the venue.',
          'Delegates scan the QR code with their phone.',
          'They enter their email address (the one used when booking).',
          'An OTP (one-time passcode) is sent to their email.',
          'After entering the OTP, they access their personal learning dashboard.',
          'From the dashboard, they complete two on-the-day forms:',
          '  1. TD-07 Candidate Induction Form — personal details, employer info, emergency contacts.',
          '  2. TD-29 Health & Safety Induction — H&S checklist reviewed and signed with the instructor.',
          'Both forms require digital signatures from the candidate and instructor.',
        ],
      },
      {
        id: 'view-submissions',
        title: 'Viewing Completed Onboarding Forms',
        roles: [...ALL_STAFF, 'company_trainer'],
        steps: [
          'Expand an order on the Orders page.',
          "Click the 'Onboarding Forms' tab.",
          'All submitted forms (TD-02, TD-07, TD-29) are listed per delegate.',
          'Click on a submission to view the full form data.',
          'Forms can be exported for record-keeping.',
        ],
      },
    ],
  },
  {
    id: 'checkout',
    title: 'Booking a Course & Taking Payment',
    icon: ShoppingCart,
    description: 'The full customer journey — finding a course, choosing a date, the cart, and paying by card, invoice or credit.',
    roles: EVERYONE,
    procedures: [
      {
        id: 'booking-flow',
        title: 'Course Booking Flow (Public Website)',
        roles: EVERYONE,
        steps: [
          "Browse courses on the public website and click 'Book Now'.",
          'Select the number of delegates and a start date.',
          'Enter billing details: Full Name, Email, Phone.',
          'Enter delegate details: First Name, Last Name, Email for each delegate.',
          'Optionally apply a Discount Code.',
          'Choose payment method: Card (Stripe), Company Credit, or Invoice (if applicable).',
          'Complete payment.',
          'A confirmation page shows booking details, joining instructions, and PPE requirements.',
          'A confirmation email with PDF invoice is sent to the billing email.',
          'Pre-course questionnaires (TD-02) are automatically sent to each delegate.',
        ],
      },
      {
        id: 'choosing-date',
        title: 'Choosing a Course Date (Availability Calendar)',
        roles: EVERYONE,
        steps: [
          'On a course page the "Course Start Date" calendar shows only dates the course can actually run — a date is selectable only when an assigned trainer is available and venue resources (rooms/yards) have capacity.',
          'Past dates, dates the trainer is unavailable, and bank holidays are greyed out. If a course has no trainers assigned it shows "No trainers assigned – dates unavailable".',
          'Pick a date; if more than one venue can run it that day, choose from "Available Locations".',
          '"Dates in progress" lists courses already running that you can still "Book to Join" where seats remain.',
          'E-learning (online) courses have no date — they show "start anytime" and skip the calendar.',
          'Once a date (and venue) is chosen, "Book Now" opens the booking dialog, or "Add to Cart" saves it to book alongside other courses.',
        ],
      },
      {
        id: 'cart-checkout',
        title: 'Booking Multiple Courses (the Cart)',
        roles: EVERYONE,
        steps: [
          'Use "Add to Cart" on each course/date to build a multi-course order, then open the Cart (/cart) from the navbar.',
          'Each cart line shows the course, date, venue, delegate count and seats remaining. Expand a line to add/edit delegates (name, email, phone); a company login can pick existing delegates.',
          'Seat limits are enforced across cart lines for the same course/date, so you cannot over-book a date.',
          'The Order Summary totals everything with VAT. "Book This Only" checks out a single line; "Proceed to Checkout" books the whole cart at once.',
          'You must be signed in to check out — guests are sent to sign in or register first.',
        ],
      },
      {
        id: 'pay-by-card',
        title: 'Paying by Card (Stripe)',
        roles: EVERYONE,
        steps: [
          'At checkout, confirm your contact details and the number of delegates (capped at seats remaining), then enter each delegate’s details.',
          'Choose "Card Payment". The system creates the order and a Stripe payment intent, then shows the secure Stripe card form (card, plus wallets where available).',
          'Enter card details and pay the VAT-inclusive total; any 3-D Secure check is handled inline.',
          'On success the order is confirmed (verified via Stripe), a confirmation email + PDF invoice is sent, the TD-02 pre-course form goes to each delegate, and you land on the confirmation page.',
          'On a white-label tenant site, the card charge goes through that company’s own Stripe account.',
        ],
      },
      {
        id: 'pay-invoice-credit',
        title: 'Paying on Account (Invoice / Company Credit)',
        roles: [...ALL_STAFF, 'company_manager'],
        steps: [
          'If you are booking under a company that has a credit account with available balance, a "Pay on Invoice" option appears at checkout.',
          'Choosing it confirms the booking immediately and reserves the gross (incl-VAT) amount against the company’s available credit until the invoice is settled (default 30-day terms).',
          'If the company has no credit account, or not enough available balance, only card payment is offered.',
          'Staff track and settle these under Finance and Company Detail › Credit.',
        ],
      },
      {
        id: 'discounts-referrals-credit',
        title: 'Discounts, Referrals & Credit Notes at Checkout',
        roles: EVERYONE,
        steps: [
          'Enter a discount code on the delegates step and click Apply; it is validated server-side (scope, dates, usage limit) and the total updates. The stored order price is net of the discount.',
          'A referral link (a ?ref=… URL) applies a 15% referral discount automatically when the code is valid.',
          'Any credit notes on your account (or your company) can be ticked to apply their balance; if they cover the whole bill the order completes with no card payment.',
        ],
      },
      {
        id: 'prereq-seats',
        title: 'Prerequisites & Seat Limits',
        roles: EVERYONE,
        steps: [
          'If a course has mandatory prerequisites you have not completed, booking is blocked until those certificates exist; recommended prerequisites show a warning only.',
          'The number of delegates is capped at the seats remaining for the chosen date, with a live "X seats remaining" / "Fully booked" hint.',
          'Room/yard capacity is re-checked on submit so multi-venue days cannot be over-booked.',
        ],
      },
      {
        id: 'after-payment',
        title: 'After You Book (Confirmation & Next Steps)',
        roles: EVERYONE,
        steps: [
          'You are taken to the confirmation page (/checkout/success) showing booking details, joining info and PPE requirements.',
          'A confirmation email with a PDF invoice is sent to the billing email.',
          'Each delegate is emailed the TD-02 pre-course questionnaire to complete before the course.',
          'Joining instructions follow automatically (24 hours after booking, or immediately if the course is within 48 hours).',
        ],
      },
      {
        id: 'waitlist-join',
        title: 'Joining the Waitlist for a Full Course',
        roles: EVERYONE,
        steps: [
          'When a course date is fully booked, a "Join Waitlist" option is offered instead of booking.',
          'Enter your contact details, preferred date and number of delegates.',
          'Staff see waitlist entries under Operations › Waitlist and email you when a space opens; you then complete a normal booking.',
        ],
      },
      {
        id: 'joining-instructions',
        title: 'Joining Instructions Automation',
        roles: [...ALL_STAFF],
        steps: [
          'Joining instructions are automatically scheduled after booking.',
          'If the course date is more than 48 hours away, instructions are sent 24 hours after booking.',
          'If the course is within 48 hours, instructions are sent immediately.',
          'Instructions include: course title, date, venue details, and PPE requirements.',
          'Instructions are sent to the billing contact and all delegates.',
          'You can manually trigger joining instructions from the order detail view.',
        ],
      },
    ],
  },
  {
    id: 'certificates',
    title: 'Certificate Management',
    icon: FileText,
    description: 'Issuing, tracking, and managing delegate certificates and expiry dates.',
    roles: [...ALL_STAFF, 'company_manager'],
    procedures: [
      {
        id: 'issue-certificate',
        title: 'Issuing a Certificate',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Certificates from the sidebar.',
          "Click 'Issue Certificate'.",
          "Enter the delegate's email address.",
          'Select the course the certificate relates to.',
          'Optionally link to a company and order.',
          'Enter the certificate number, issue date, and expiry date.',
          'Upload the certificate file (PDF or image).',
          'Add any relevant notes.',
          "Click 'Issue' to save the certificate.",
        ],
      },
      {
        id: 'track-expiry',
        title: 'Tracking Certificate Expiry',
        roles: [...ALL_STAFF, 'company_manager'],
        steps: [
          'The Certificates page shows all certificates with their expiry status.',
          'Certificates are colour-coded: Green (valid), Amber (expiring within 30 days), Red (expired).',
          'Use the status filter to quickly find expired or expiring certificates.',
          'Company Managers see only certificates for delegates in their company.',
          'Set up automated expiry alerts to notify delegates and managers before certificates expire.',
        ],
      },
      {
        id: 'revoke-certificate',
        title: 'Revoking or Updating a Certificate',
        roles: [...ALL_STAFF],
        steps: [
          'Find the certificate in the Certificates list.',
          'Click the edit button to modify details.',
          "Change the status to 'Revoked' if the certificate is no longer valid.",
          'Update expiry dates or notes as needed.',
          'All changes are logged in the audit trail.',
        ],
      },
    ],
  },
  {
    id: 'services',
    title: 'Compliance & AI Services',
    icon: Monitor,
    description: 'Managing company service entitlements, AI tools, and compliance features.',
    roles: [...ALL_STAFF, 'company_manager'],
    // The Compliance group is hidden from the sidebar while in development, so
    // this section is hidden from the manual too (for everyone) until it ships.
    group: 'Compliance',
    procedures: [
      {
        id: 'enable-services',
        title: 'Enabling Services for a Company',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Companies and click on the company name.',
          "Go to the 'Services' tab.",
          'Toggle on the services you want to enable: AI Risk Assessor, AR Engineer Support, Compliance Documents, Skills Gap Analysis.',
          "Each service becomes immediately available to the company's portal users.",
          'To disable a service, toggle it off. Existing data is preserved.',
        ],
      },
      {
        id: 'global-services',
        title: 'Viewing Global Services Dashboard',
        roles: [...ALL_STAFF],
        steps: [
          "Navigate to Services from the sidebar under 'Compliance & Services'.",
          'View the total number of active subscriptions across all companies.',
          'See usage metrics broken down by service type.',
          'Monitor which companies are using which services.',
          'Use this data to identify upsell opportunities and track engagement.',
        ],
      },
      {
        id: 'ai-risk-assessor',
        title: 'Using the AI Risk Assessor (Company Portal)',
        roles: ['company_manager'],
        steps: [
          'Log in to the Company Portal.',
          "Navigate to the 'Risk Assessor' tab (only visible if the service is enabled).",
          'Enter the job details: Job Type, Location, and Task Description.',
          "Click 'Generate Risk Assessment'.",
          'The AI generates a structured RAMS document including hazards, controls, risk ratings, and PPE requirements.',
          'Review the assessment and download or share as needed.',
          'All assessments are logged for audit purposes.',
        ],
      },
      {
        id: 'ar-engineer-support',
        title: 'Using AR Engineer Support (Company Portal)',
        roles: ['company_manager'],
        steps: [
          "Navigate to the 'Engineer Support' tab in the Company Portal.",
          'Start a new conversation or continue an existing one.',
          'Type your technical question relating to NRSWA, safety regulations, or engineering practices.',
          'The AI provides streaming responses with contextual guidance.',
          'Conversation history is saved and can be reviewed later.',
        ],
      },
      {
        id: 'compliance-docs',
        title: 'Generating Compliance Documents (Company Portal)',
        roles: ['company_manager'],
        steps: [
          "Navigate to the 'Compliance Docs' tab in the Company Portal.",
          'Select the document type: Toolbox Talk, Permit to Work, or Site Induction.',
          'Enter the required details (topic, site name, etc.).',
          "Click 'Generate' to create the document.",
          'Review, edit, and download the generated template.',
        ],
      },
      {
        id: 'skills-gap-analysis',
        title: 'Using Skills Gap Analysis (Company Portal)',
        roles: ['company_manager'],
        steps: [
          "Navigate to the 'Skills Gap' tab in the Company Portal.",
          "First, set up Job Roles: click 'Manage Roles' and create roles relevant to your organisation (e.g., Streetworks Operative, Supervisor).",
          'For each role, add Required Courses by selecting from the course catalogue.',
          'Mark courses as Mandatory or Optional.',
          'Assign delegates to their job roles from the delegate list.',
          "The Skills Gap Matrix automatically cross-references delegates' certificates against role requirements.",
          'Status indicators show: Valid, Expiring (within 30 days), Missing or Expired.',
          "Click 'Book Courses' to quickly book missing certifications.",
        ],
      },
    ],
  },
  {
    id: 'individual-accounts',
    title: 'Individual Accounts',
    icon: Users,
    description: 'Managing delegate, company manager, and trainer accounts.',
    roles: [...ALL_STAFF],
    procedures: [
      {
        id: 'view-accounts',
        title: 'Viewing Individual Accounts',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Accounts from the sidebar.',
          'The page shows all non-system users: Delegates, Company Managers, and Trainers.',
          'Use the role filter dropdown to show specific account types.',
          'Search by name or email to find specific accounts.',
          'System-level roles (sys_admin, sys_manager) are managed separately under System > User Roles.',
        ],
      },
      {
        id: 'edit-account',
        title: 'Editing an Account',
        roles: [...ALL_STAFF],
        steps: [
          'Click on an account to view their profile details.',
          'View their assigned roles, linked company (if any), and registration date.',
          'Edit profile information as needed.',
          "View the user's order history, certificates, and form submissions.",
        ],
      },
    ],
  },
  {
    id: 'revenue',
    title: 'Revenue Analytics',
    icon: FileText,
    description: 'Tracking revenue, sales performance, and financial reporting.',
    roles: [...ALL_STAFF],
    procedures: [
      {
        id: 'view-revenue',
        title: 'Viewing Revenue Dashboard',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Revenue Analytics from the sidebar.',
          'View total revenue, order count, and average order value.',
          'Charts show revenue trends over time.',
          'Filter by date range, course category, or company.',
          'Compare revenue across different channels (marketplace, white-label, company credit).',
        ],
      },
    ],
  },
  {
    id: 'audit-log',
    title: 'Audit Log',
    icon: Shield,
    description: 'Viewing system activity and audit trail for compliance.',
    roles: ['sys_admin', 'sys_manager', 'admin'],
    procedures: [
      {
        id: 'view-audit-log',
        title: 'Using the Audit Log',
        roles: ['sys_admin', 'sys_manager', 'admin'],
        steps: [
          'Navigate to Audit Log from the sidebar under System.',
          'The log shows all significant actions performed in the system.',
          'Each entry includes: timestamp, user email, action type, affected entity, and details.',
          'Use filters to narrow by action type (create, update, delete), entity type, or date range.',
          'Search for specific users or entities.',
          'The audit log is read-only — entries cannot be modified or deleted.',
        ],
      },
    ],
  },
  {
    id: 'prerequisites',
    title: 'Course Prerequisites',
    icon: GraduationCap,
    description: 'Configuring course prerequisites and dependency chains.',
    roles: [...ALL_STAFF],
    procedures: [
      {
        id: 'set-prerequisites',
        title: 'Setting Course Prerequisites',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Course Prerequisites from the sidebar.',
          'Select the course that requires prerequisites.',
          "Click 'Add Prerequisite'.",
          'Select the prerequisite course from the dropdown.',
          'Mark whether the prerequisite is Mandatory or Recommended.',
          'Save the prerequisite link.',
          'Prerequisites are displayed on the course detail page and enforced during booking.',
        ],
      },
    ],
  },
  {
    id: 'waitlist',
    title: 'Waitlist Management',
    icon: ClipboardList,
    description: 'Managing course waitlist entries when courses are fully booked.',
    roles: [...ALL_STAFF],
    procedures: [
      {
        id: 'manage-waitlist',
        title: 'Managing the Waitlist',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to Waitlist from the sidebar.',
          'View all waitlist entries across courses.',
          'Each entry shows the contact name, email, course, preferred date, and number of delegates.',
          "When a space becomes available, click 'Notify' to send an email to the waiting customer.",
          "Update the status to 'Notified' or 'Booked' as appropriate.",
          'Delete entries that are no longer relevant.',
        ],
      },
    ],
  },
  {
    id: 'company-portal',
    title: 'Company Portal',
    icon: Building2,
    description: 'Self-service portal for company managers to manage their team and bookings.',
    roles: ['company_manager'],
    procedures: [
      {
        id: 'portal-overview',
        title: 'Company Portal Overview',
        roles: ['company_manager'],
        steps: [
          'Log in with your company manager credentials.',
          'You are automatically redirected to the Company Portal.',
          'The portal contains tabs for: Delegates, Orders, Certificates, Compliance, and AI Tools.',
          'All data is scoped to your company only.',
        ],
      },
      {
        id: 'manage-delegates-portal',
        title: 'Managing Delegates (Company Portal)',
        roles: ['company_manager'],
        steps: [
          "Go to the 'Delegates' tab.",
          'View all delegates registered under your company.',
          "Add new delegates individually or use 'Bulk Import' to upload a CSV file.",
          'Edit delegate details by clicking on their name.',
          "View each delegate's training history and certificate status.",
        ],
      },
      {
        id: 'compliance-matrix-portal',
        title: 'Using the Compliance Matrix',
        roles: ['company_manager'],
        steps: [
          "Go to the 'Compliance' tab.",
          'The matrix shows all delegates against required certifications.',
          'Green = Valid certificate, Amber = Expiring within 30 days, Red = Expired or missing.',
          'Click on any cell to view the certificate details.',
          'Use the summary statistics to track overall team compliance percentage.',
        ],
      },
    ],
  },
  {
    id: 'delegate-dashboard',
    title: 'Delegate Dashboard & Profile',
    icon: Users,
    description: 'Individual delegate self-service for viewing certificates and course history.',
    roles: ['delegate'],
    procedures: [
      {
        id: 'delegate-profile',
        title: 'Using the Delegate Profile',
        roles: ['delegate'],
        steps: [
          'Log in to access your personal dashboard.',
          'View your upcoming courses and training history.',
          'Access your Certificate Wallet to view and download all certificates.',
          'Track e-learning progress and continue where you left off.',
          'Complete onboarding forms (TD-02, TD-07, TD-29) when required.',
          'Update your personal details and contact information.',
        ],
      },
    ],
  },
  {
    id: 'provider-portal',
    title: 'Provider Portal',
    icon: GraduationCap,
    description: 'Self-service portal for training company trainers to manage their assignments.',
    roles: ['company_trainer'],
    procedures: [
      {
        id: 'provider-overview',
        title: 'Provider Portal Overview',
        roles: ['company_trainer'],
        steps: [
          'Log in with your company trainer credentials.',
          'View your assigned courses and upcoming bookings.',
          'See delegate lists for each booking.',
          'Access onboarding form submissions for your courses.',
          'Track your availability and manage date overrides.',
          'View revenue and booking statistics for your courses.',
        ],
      },
    ],
  },
  {
    id: 'auth',
    title: 'Authentication & Security',
    icon: Shield,
    description: 'Login process, password reset, and account security.',
    roles: EVERYONE,
    procedures: [
      {
        id: 'admin-login',
        title: 'Admin Login (Two-Factor Authentication)',
        roles: [...ALL_STAFF],
        steps: [
          'Navigate to the login page.',
          'Enter your email address and password.',
          'After credentials are verified, a 6-digit OTP code is sent to your email.',
          'Enter the OTP code to complete authentication.',
          'You are redirected to the admin dashboard. Trusted devices skip the OTP for 6 hours.',
        ],
      },
      {
        id: 'password-reset',
        title: 'Resetting Your Password',
        roles: EVERYONE,
        steps: [
          "On the login page, click 'Forgot password?'.",
          "Enter your email address and click 'Send Reset Link'.",
          'Check your email for a password reset link.',
          'Click the link to open the password reset page.',
          'Enter your new password and confirm it.',
          "Click 'Update Password' to save.",
          'You are redirected to the login page to sign in with your new password.',
        ],
      },
      {
        id: 'user-registration',
        title: 'User Registration',
        roles: EVERYONE,
        steps: [
          'Navigate to the Register page.',
          'Choose between Delegate registration or Company registration.',
          'For Delegate registration: enter email, password, and full name. Optionally enter a referral code.',
          'For Company registration: enter company details, contact information, and admin credentials.',
          'Verify your email address via the confirmation link sent to your inbox.',
          "Company registrations are created in 'Draft' status and require admin approval before becoming active.",
        ],
      },
      {
        id: 'account-access-notes',
        title: 'Email Verification & Access Control',
        roles: EVERYONE,
        body: [
          'New accounts must verify their email via a link before they can sign in fully; some sensitive actions re-prompt for your password.',
          'If you open a page your role is not allowed to use, the system shows an "Access Denied" message instead of the page — ask a System Admin to grant it at Role Management if you need access.',
          'Sign out is always available from the top bar or sidebar; otherwise sessions expire after a period of inactivity.',
        ],
      },
    ],
  },
  {
    id: 'white-label',
    title: 'White-Label & Tenant Portals',
    icon: Monitor,
    description: 'Managing branded company portals, subdomains, and tenant content.',
    roles: [...ALL_STAFF],
    procedures: [
      {
        id: 'tenant-home',
        title: 'What the Branded (White-Label) Site Looks Like',
        roles: [...ALL_STAFF],
        body: [
          'When a company’s branding is active, visiting its subdomain shows a fully branded homepage — the company logo, colours, hero image/video, tagline and contact details, with that company’s own featured courses, blog/news and testimonials.',
          'Browsing, the course calendar, the cart and checkout all work exactly like the main site, but card payments are taken through that company’s own Stripe account.',
          'The Locktel pages (/locktel…) are a managed example of such a tenant.',
        ],
      },
      {
        id: 'setup-white-label',
        title: 'Setting Up a White-Label Portal',
        roles: [...ALL_STAFF],
        steps: [
          "Navigate to the training company's detail page.",
          "Go to the 'Branding' tab.",
          "Set the subdomain (e.g., 'acme-training' creates acme-training.yoursite.com).",
          'Upload the company logo.',
          'Configure brand colours: Primary, Secondary, Background, Font, Card, and Card Font colours.',
          'Set a hero image or video URL for the homepage.',
          'Add a tagline displayed over the hero section.',
          'Configure contact details: email, phone, address, and opening hours.',
          "Toggle 'Active' to publish the portal.",
          'Use the preview URL to verify the branding before going live.',
        ],
      },
      {
        id: 'manage-tenant-content',
        title: 'Managing Tenant Content (Featured Courses, Blog, Testimonials)',
        roles: [...ALL_STAFF],
        steps: [
          "In the company detail page, use the 'Featured Courses' tab to select which courses appear on the company's homepage.",
          "Use the 'Blog / News' tab to create and publish articles specific to the company's portal.",
          "Use the 'Testimonials' tab to add and manage customer reviews displayed on the portal.",
          'All content is scoped to the specific company and only appears on their subdomain.',
        ],
      },
      {
        id: 'stripe-connect',
        title: 'Configuring Company Stripe Payments',
        roles: [...ALL_STAFF],
        steps: [
          "Payments on white-label portals use the training company's own Stripe account.",
          "Go to the company's Branding tab.",
          "Enter the company's Stripe publishable key and secret key.",
          "All transactions on the company's subdomain will be processed through their Stripe account.",
          'The platform fee structure is handled via Stripe Connect configuration.',
        ],
      },
    ],
  },
];

export const VIEW_AS_OPTIONS: { value: 'all' | RoleKey; label: string }[] = [
  { value: 'all', label: 'Everything' },
  { value: 'sys_manager', label: 'System Manager' },
  { value: 'admin', label: 'Admin' },
  { value: 'manager', label: 'Manager' },
  { value: 'company_manager', label: 'Company Manager' },
  { value: 'company_trainer', label: 'Company Trainer' },
  { value: 'delegate', label: 'Delegate' },
];

// Source for the "Pages & Links Reference". Each page lists the roles that can
// open it (matching the role_page grid). The component renders only the pages
// the current viewer can access, grouped. Hidden pages (Services, Locktel CMS)
// and the hidden Compliance group are intentionally omitted — hidden from the
// sidebar means hidden from the manual too.
const PAGE_REFERENCE: { group: string; pages: { text: string; roles: RoleKey[] }[] }[] = [
  {
    group: 'Public website (no login)',
    pages: [
      { text: 'Home (/) — marketing homepage with featured courses.', roles: EVERYONE },
      { text: 'Courses (/courses) and Course detail (/course/{slug}) — browse and book courses.', roles: EVERYONE },
      { text: 'Cart (/cart) and Checkout success (/checkout/success) — basket and post-payment confirmation.', roles: EVERYONE },
      { text: 'E-Learning (/e-learning) — online courses; enrolled learners launch via /elearning/{enrolment}/launch (VideoTile).', roles: EVERYONE },
      { text: 'About, Contact, Terms, Privacy, SMART Awards (/smart-awards), NRSWA Courses (/nrswa-courses) — information pages.', roles: EVERYONE },
      { text: 'Accept Invite (/accept-invite) and Pre-Course Form (/onboarding/pre-course) — reached from email links.', roles: EVERYONE },
    ],
  },
  {
    group: 'Dashboard & Operations',
    pages: [
      { text: 'Dashboard (/admin) — home screen with KPI counts and action alerts. Portal roles opening /admin are redirected to their own portal.', roles: [...ALL_STAFF, 'company_manager', 'company_trainer', 'delegate'] },
      { text: 'Bookings / Orders (/admin/orders) — course orders. Staff can assign trainer/venue, refund, cancel and resend emails; company managers see their company; delegates see their own.', roles: [...ALL_STAFF, 'company_manager', 'delegate'] },
      { text: 'Training Calendar (/admin/calendar) — confirmed bookings by date.', roles: [...ALL_STAFF] },
      { text: 'Availability (/admin/availability) — trainer weekly availability and date overrides.', roles: [...ALL_STAFF] },
      { text: 'Cert Manager (/admin/certificates) — issue, track and revoke certificates; company managers and delegates see their own.', roles: [...ALL_STAFF, 'company_manager', 'delegate'] },
      { text: 'Waitlist (/admin/waitlist) — waiting customers for full courses; notify when a space frees.', roles: [...ALL_STAFF] },
      { text: 'Course Requests (/admin/course-requests) — booking requests awaiting approval.', roles: [...ALL_STAFF, 'company_manager'] },
      { text: 'Date Change Requests (/admin/date-changes) — reschedule requests to approve or reject.', roles: [...ALL_STAFF, 'company_manager', 'company_trainer'] },
      { text: 'Location Overrides (/admin/location-overrides) — block venue resources.', roles: ['sys_admin', 'sys_manager'] },
      { text: "My Schedule (/admin/my-schedule) — a trainer's own assignments.", roles: ['company_trainer'] },
      { text: 'Delegate Detail (/admin/delegates/{id}) — the full record for one delegate.', roles: [...ALL_STAFF] },
    ],
  },
  {
    group: 'Training',
    pages: [
      { text: 'Courses (/admin/courses, plus new/edit) — create and edit courses, the venue-schedule grid and e-learning links.', roles: [...ALL_STAFF] },
      { text: 'Categories (/admin/categories) — course categories (NRSWA / SMART Awards / General) and sub-categories.', roles: [...ALL_STAFF] },
      { text: 'Assignments (/admin/course-assignments) — link trainers (and default venues) to courses.', roles: [...ALL_STAFF] },
      { text: 'Prerequisites (/admin/prerequisites) — required / recommended course chains.', roles: [...ALL_STAFF] },
      { text: 'E-Learning (/admin/e-learning) — manage the online-course catalogue and enrolments.', roles: [...ALL_STAFF] },
      { text: 'Locations / Venues (/admin/venues) — venues with rooms and yards.', roles: [...ALL_STAFF] },
    ],
  },
  {
    group: 'People',
    pages: [
      { text: 'Trainers (/admin/trainers) — trainer records, company links and availability.', roles: [...ALL_STAFF] },
      { text: 'Companies (/admin/companies) — training & purchasing companies.', roles: [...ALL_STAFF] },
      { text: 'Company Detail (/admin/companies/{id}) — one company: credit, branding, services, delegates, finance and Stripe; company managers see their own company.', roles: [...ALL_STAFF, 'company_manager'] },
      { text: 'Accounts (/admin/accounts) — non-system user accounts (delegates, company managers, trainers).', roles: [...ALL_STAFF] },
    ],
  },
  {
    group: 'Commercial',
    pages: [
      { text: 'Revenue (/admin/revenue) — revenue analytics and trends.', roles: [...ALL_STAFF] },
      { text: 'Finance (/admin/finance) — outstanding invoices and a financial overview; company managers see their own.', roles: [...ALL_STAFF, 'company_manager'] },
      { text: 'Discounts (/admin/discount-codes) — promo and company/user discount codes.', roles: [...ALL_STAFF] },
      { text: 'Credit Notes (/admin/credit-notes) — refund-derived store credit.', roles: [...ALL_STAFF] },
    ],
  },
  {
    group: 'Tools',
    pages: [
      { text: 'SOPs / this manual (/admin/sops) — the resource you are reading, filtered to your role.', roles: EVERYONE },
    ],
  },
  {
    group: 'System',
    pages: [
      { text: 'User Roles (/admin/user-roles) — assign/remove roles and view pending invites.', roles: ['sys_admin', 'admin'] },
      { text: 'Role Management (/admin/role-management) — the role-to-page access grid.', roles: ['sys_admin'] },
      { text: 'Audit Log (/admin/audit-log) — every significant action in the system.', roles: ['sys_admin', 'sys_manager', 'admin'] },
      { text: 'Email Logs (/admin/email-logs) — sent-email history.', roles: ['sys_admin', 'sys_manager', 'admin'] },
    ],
  },
  {
    group: 'Portals',
    pages: [
      { text: 'Company Portal (/company-portal) — company-manager self-service: delegates, orders, certificates and tools.', roles: ['company_manager'] },
      { text: 'Provider Portal (/provider-portal) — company-trainer view: schedule, assigned courses, delegate lists and stats.', roles: ['company_trainer'] },
      { text: "Delegate Dashboard (/delegate-dashboard) and Delegate Profile (/delegate-profile) — a learner's courses, certificate wallet, e-learning and onboarding forms.", roles: ['delegate'] },
      { text: 'Onboarding (/onboarding, /onboarding/forms) — on-the-day induction forms.', roles: [...ALL_STAFF, 'company_trainer', 'delegate'] },
      { text: 'Profile (/profile) — your own account details.', roles: EVERYONE },
    ],
  },
];

export interface SopManualProps {
  /**
   * Roles used to filter the manual. The caller decides these — a staff
   * viewer's real (or globally-previewed) roles, or a fixed role such as
   * ['delegate'] when the manual is embedded in the delegate dashboard.
   */
  effectiveRoles: string[];
  title?: string;
  description?: string;
  /** Show the "Download Manual" button (plain-text export of what's visible). */
  showDownload?: boolean;
  /**
   * Enable the interactive walkthroughs. They navigate around the admin area,
   * so this only makes sense inside /admin — leave off when embedded elsewhere.
   */
  enableTutorials?: boolean;
  /** Optional staff-only "Viewing as" controls, rendered above the search box. */
  viewAsControls?: ReactNode;
}

const SopManual = ({
  effectiveRoles,
  title = 'System Manual & SOPs',
  description = 'How the system works, what every link does, and step-by-step guides — filtered to your role.',
  showDownload = true,
  // Interactive walkthroughs aren't a feature we ship — default off so the
  // "Start Interactive Walkthrough" CTAs never render.
  enableTutorials = false,
  viewAsControls,
}: SopManualProps) => {
  const [search, setSearch] = useState('');
  const [activeCategory, setActiveCategory] = useState<string | null>(null);
  const [zoomedImage, setZoomedImage] = useState<string | null>(null);
  const [activeTutorial, setActiveTutorial] = useState<{ procedureId: string; title: string } | null>(null);

  // System Admin (real or previewed) sees the entire manual.
  const seesEverything = effectiveRoles.includes('sys_admin');
  const canSee = (tags: RoleKey[]) => seesEverything || tags.some((t) => effectiveRoles.includes(t));

  // Pages & Links Reference is generated per-viewer so it lists ONLY the pages
  // this role can actually open (and never anything from a hidden group).
  const buildPagesProcedures = (): SOPProcedure[] =>
    PAGE_REFERENCE.map((g) => {
      const lines = g.pages.filter((p) => canSee(p.roles)).map((p) => p.text);
      return lines.length
        ? {
            id: 'pages-' + g.group.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
            title: g.group,
            roles: [] as RoleKey[],
            body: lines,
          }
        : null;
    }).filter((p): p is SOPProcedure => p !== null);

  // A category whose group is hidden in the sidebar (e.g. Compliance) is hidden
  // here for everyone too.
  const isHiddenCategory = (cat: SOPCategory) => !!cat.group && HIDDEN_GROUPS.has(cat.group);

  // Role-filter first, then apply the text search on top of what's visible.
  const roleVisibleCategories = sopCategories
    .filter((cat) => !HIDDEN_SOP_CATEGORY_IDS.has(cat.id))
    .filter((cat) => !isHiddenCategory(cat))
    .filter((cat) => canSee(cat.roles))
    .map((cat) =>
      cat.id === 'pages'
        ? { ...cat, procedures: buildPagesProcedures() }
        : { ...cat, procedures: cat.procedures.filter((p) => canSee(p.roles)) },
    )
    .filter((cat) => cat.procedures.length > 0);

  const matchesSearch = (proc: SOPProcedure) => {
    const q = search.toLowerCase();
    return (
      proc.title.toLowerCase().includes(q) ||
      (proc.steps ?? []).some((s) => s.toLowerCase().includes(q)) ||
      (proc.body ?? []).some((s) => s.toLowerCase().includes(q)) ||
      roleBadges(proc.roles).some((r) => r.toLowerCase().includes(q))
    );
  };

  const filteredCategories = roleVisibleCategories
    .map((cat) => ({ ...cat, procedures: cat.procedures.filter(matchesSearch) }))
    .filter((cat) => cat.procedures.length > 0);

  const handleDownloadPDF = () => {
    let content = 'UTILITY TRAINING CENTRE — SYSTEM MANUAL (SOPs)\n\n';
    roleVisibleCategories.forEach((cat) => {
      content += `\n${'='.repeat(60)}\n${cat.title.toUpperCase()}\n${cat.description}\n${'='.repeat(60)}\n`;
      cat.procedures.forEach((proc) => {
        content += `\n--- ${proc.title} ---\n`;
        content += `Roles: ${roleBadges(proc.roles).join(', ')}\n\n`;
        (proc.steps ?? []).forEach((step, i) => {
          content += `  ${i + 1}. ${step}\n`;
        });
        (proc.body ?? []).forEach((para) => {
          content += `  ${para}\n`;
        });
        if (proc.notes) {
          content += `\n  Notes:\n`;
          proc.notes.forEach((n) => (content += `    • ${n}\n`));
        }
        content += '\n';
      });
    });

    const blob = new Blob([content], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'UTC_System_Manual.txt';
    a.click();
    URL.revokeObjectURL(url);
  };

  const renderProcedure = (proc: SOPProcedure) => (
    <AccordionItem key={proc.id} value={proc.id} className="border rounded-lg px-4">
      <AccordionTrigger className="hover:no-underline">
        <div className="flex items-center gap-3 text-left">
          <span className="font-medium">{proc.title}</span>
          <div className="flex gap-1 flex-wrap">
            {roleBadges(proc.roles).map((role) => (
              <Badge key={role} variant="outline" className="text-xs">
                {role}
              </Badge>
            ))}
          </div>
        </div>
      </AccordionTrigger>
      <AccordionContent>
        {proc.steps && (
          <ol className="list-decimal list-inside space-y-2 text-sm text-foreground">
            {proc.steps.map((step, i) => (
              <li key={i} className={step.startsWith('  ') ? 'ml-6 list-disc' : ''}>
                {step.trim()}
              </li>
            ))}
          </ol>
        )}
        {proc.body && (
          <div className="space-y-2 text-sm text-foreground leading-relaxed">
            {proc.body.map((para, i) => (
              <p key={i}>{para}</p>
            ))}
          </div>
        )}
        {proc.notes && (
          <div className="mt-3 p-3 bg-muted rounded-md">
            <p className="text-xs font-medium text-muted-foreground mb-1">Notes:</p>
            <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1">
              {proc.notes.map((n, i) => (
                <li key={i}>{n}</li>
              ))}
            </ul>
          </div>
        )}
        {enableTutorials && tutorialStepMap[proc.id] && (
          <Button
            variant="outline"
            size="sm"
            className="mt-4 gap-2"
            onClick={() => setActiveTutorial({ procedureId: proc.id, title: proc.title })}
          >
            <Play className="h-3.5 w-3.5" />
            Start Interactive Walkthrough
          </Button>
        )}
      </AccordionContent>
    </AccordionItem>
  );

  return (
      <div>
        <div className="flex items-center justify-between mb-6">
          <div>
            <h1 className="text-2xl font-bold text-foreground flex items-center gap-2">
              <BookOpen className="h-6 w-6" />
              {title}
            </h1>
            <p className="text-sm text-muted-foreground mt-1">{description}</p>
          </div>
          {showDownload && (
            <Button variant="outline" onClick={handleDownloadPDF}>
              <Download className="mr-2 h-4 w-4" /> Download Manual
            </Button>
          )}
        </div>

        {/* Staff-only "Viewing as" controls, supplied by the caller. */}
        {viewAsControls}

        <div className="relative mb-6">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
          <Input
            placeholder="Search the manual — pages, processes, steps, or roles..."
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            className="pl-9"
          />
        </div>

        {/* Category Cards */}
        {!search && !activeCategory && (
          <div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
            {roleVisibleCategories.map((cat) => (
              <Card
                key={cat.id}
                className="cursor-pointer hover:shadow-md transition-shadow border-border overflow-hidden"
                onClick={() => setActiveCategory(cat.id)}
              >
                {cat.screenshot && (
                  <div className="h-32 overflow-hidden border-b border-border">
                    <img
                      src={cat.screenshot}
                      alt={`${cat.title} screenshot`}
                      className="w-full h-full object-cover object-top"
                    />
                  </div>
                )}
                <CardHeader className="pb-2">
                  <CardTitle className="text-base flex items-center gap-2">
                    <cat.icon className="h-5 w-5 text-primary" />
                    {cat.title}
                  </CardTitle>
                </CardHeader>
                <CardContent>
                  <p className="text-sm text-muted-foreground">{cat.description}</p>
                  <Badge variant="secondary" className="mt-2">
                    {cat.procedures.length} {cat.procedures.length === 1 ? 'entry' : 'entries'}
                  </Badge>
                </CardContent>
              </Card>
            ))}
          </div>
        )}

        {/* Category Detail / Search Results View */}
        {(activeCategory || search) && (
          <div>
            {!search && (
              <Button variant="ghost" className="mb-4" onClick={() => setActiveCategory(null)}>
                ← Back to all sections
              </Button>
            )}
            {(search
              ? filteredCategories
              : roleVisibleCategories.filter((c) => c.id === activeCategory)
            ).map((cat) => (
              <div key={cat.id} className="mb-8">
                <h2 className="text-xl font-semibold text-foreground flex items-center gap-2 mb-4">
                  <cat.icon className="h-5 w-5 text-primary" />
                  {cat.title}
                </h2>

                {cat.screenshot && (
                  <div
                    className="relative mb-6 rounded-lg overflow-hidden border border-border cursor-pointer group"
                    onClick={() => setZoomedImage(cat.screenshot!)}
                  >
                    <img
                      src={cat.screenshot}
                      alt={`${cat.title} interface`}
                      className="w-full rounded-lg"
                    />
                    <div className="absolute inset-0 bg-background/0 group-hover:bg-background/20 transition-colors flex items-center justify-center">
                      <ZoomIn className="h-8 w-8 text-foreground opacity-0 group-hover:opacity-70 transition-opacity" />
                    </div>
                  </div>
                )}

                <Accordion type="multiple" className="space-y-2">
                  {cat.procedures.map(renderProcedure)}
                </Accordion>
              </div>
            ))}
            {search && filteredCategories.length === 0 && (
              <p className="text-center text-muted-foreground py-12">
                No entries found matching "{search}"
              </p>
            )}
          </div>
        )}

        {/* Zoom dialog */}
        <Dialog open={!!zoomedImage} onOpenChange={() => setZoomedImage(null)}>
          <DialogContent className="max-w-[90vw] max-h-[90vh] p-2">
            {zoomedImage && (
              <img
                src={zoomedImage}
                alt="Zoomed screenshot"
                className="w-full h-auto rounded"
              />
            )}
          </DialogContent>
        </Dialog>

        {/* Tutorial overlay */}
        {activeTutorial && tutorialStepMap[activeTutorial.procedureId] && (
          <TutorialOverlay
            steps={tutorialStepMap[activeTutorial.procedureId]}
            title={activeTutorial.title}
            onClose={() => setActiveTutorial(null)}
          />
        )}
      </div>
  );
};

export default SopManual;
