import { useState } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "@/components/ui/button";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import {
  Database, Code2, FileCode, LayoutGrid, Palette, GitBranch, BookOpen,
  Copy, ChevronRight, CheckCircle2
} from "lucide-react";
import { toast } from "sonner";
import MermaidDiagram from "@/pages/SystemRequirements/MermaidDiagram";

const copy = (text: string) => {
  navigator.clipboard.writeText(text);
  toast.success("Copied to clipboard");
};

/* ─────────────────── DATA ─────────────────── */

const sqlSchema = `-- ============================================================
-- RESOURCE MANAGEMENT DATABASE SCHEMA
-- PostgreSQL / Supabase — full DDL for replication
-- ============================================================

-- 1. TRAINERS — people who deliver courses
CREATE TABLE public.trainers (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  first_name      TEXT NOT NULL,
  last_name       TEXT NOT NULL,
  email           TEXT,
  phone           TEXT,
  availability_mode TEXT NOT NULL DEFAULT 'weekly',
    -- 'weekly'         = Mon-Fri recurring pattern + date overrides
    -- 'specific_dates' = only available on explicitly selected dates
  notes           TEXT,
  created_at      TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at      TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- 2. TRAINER ↔ COMPANY link (many-to-many)
CREATE TABLE public.trainer_companies (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  trainer_id  UUID NOT NULL REFERENCES trainers(id) ON DELETE CASCADE,
  company_id  UUID NOT NULL REFERENCES training_companies(id) ON DELETE CASCADE,
  UNIQUE (trainer_id, company_id)
);

-- 3. WEEKLY AVAILABILITY — default pattern per trainer
--    day_of_week: 0=Sun … 6=Sat (JS convention)
CREATE TABLE public.trainer_availability_weekly (
  id           UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  trainer_id   UUID NOT NULL REFERENCES trainers(id) ON DELETE CASCADE,
  day_of_week  INT NOT NULL CHECK (day_of_week BETWEEN 0 AND 6),
  is_available BOOLEAN NOT NULL DEFAULT true,
  UNIQUE (trainer_id, day_of_week)
);

-- 4. DATE OVERRIDES — holidays, sick days, or explicit available dates
CREATE TABLE public.trainer_availability_overrides (
  id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  trainer_id    UUID NOT NULL REFERENCES trainers(id) ON DELETE CASCADE,
  override_date DATE NOT NULL,
  is_available  BOOLEAN NOT NULL,
    -- false = day off (used in weekly mode)
    -- true  = explicitly available (used in specific_dates mode)
  reason        TEXT,
  UNIQUE (trainer_id, override_date)
);

-- 5. VENUES — physical training locations
CREATE TABLE public.venues (
  id         UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name       TEXT NOT NULL,
  address    TEXT,
  city       TEXT,
  postcode   TEXT,
  company_id UUID REFERENCES training_companies(id),
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- 6. ROOMS — indoor spaces within a venue
CREATE TABLE public.venue_rooms (
  id        UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  venue_id  UUID NOT NULL REFERENCES venues(id) ON DELETE CASCADE,
  name      TEXT NOT NULL,
  capacity  INT DEFAULT 8,
  status    TEXT NOT NULL DEFAULT 'active'
);

-- 7. YARDS — outdoor training spaces within a venue
CREATE TABLE public.venue_yards (
  id        UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  venue_id  UUID NOT NULL REFERENCES venues(id) ON DELETE CASCADE,
  name      TEXT NOT NULL,
  capacity  INT DEFAULT 8,
  shared    BOOLEAN NOT NULL DEFAULT false,
    -- shared=true means multiple courses can use it simultaneously
    -- (capacity is still enforced, but no exclusive clash detection)
  status    TEXT NOT NULL DEFAULT 'active'
);

-- 8. COURSES — the training products
CREATE TABLE public.courses (
  id               UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  title            TEXT NOT NULL,
  slug             TEXT NOT NULL UNIQUE,
  category         TEXT NOT NULL,
  days             INT NOT NULL DEFAULT 1,
  price_cents      INT NOT NULL DEFAULT 0,
  capacity         INT DEFAULT 8,   -- max delegates per session
  is_active        BOOLEAN NOT NULL DEFAULT true,
  created_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at       TIMESTAMPTZ NOT NULL DEFAULT now()
  -- ... additional metadata columns omitted for brevity
);

-- 9. COURSE ↔ TRAINER ASSIGNMENTS (with optional default venue)
CREATE TABLE public.course_trainers (
  id         UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  course_id  UUID NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
  trainer_id UUID NOT NULL REFERENCES trainers(id) ON DELETE CASCADE,
  venue_id   UUID REFERENCES venues(id),
  UNIQUE (course_id, trainer_id, venue_id)
);

-- 10. COURSE VENUE SCHEDULE — the TEMPLATE defining which resources
--     a course needs on each day/session. This is the "blueprint".
CREATE TABLE public.course_venue_schedules (
  id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  course_id     UUID NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
  venue_id      UUID NOT NULL REFERENCES venues(id),
  day_number    INT NOT NULL,          -- 1-based: Day 1, Day 2 ...
  session       TEXT NOT NULL,          -- 'AM', 'PM', or 'Full Day'
  resource_type TEXT NOT NULL,          -- 'room' or 'yard'
  resource_id   UUID NOT NULL           -- FK to venue_rooms or venue_yards
);
-- Example: A 3-day course might need:
--   Day 1 AM → Room A,  Day 1 PM → Yard B
--   Day 2 AM → Room A,  Day 2 PM → Yard B
--   Day 3 AM → Room A,  Day 3 PM → Yard C

-- 11. COURSE BOOKINGS — confirmed trainer assignments to dates
CREATE TABLE public.course_bookings (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  course_id         UUID NOT NULL REFERENCES courses(id),
  trainer_id        UUID NOT NULL REFERENCES trainers(id),
  start_date        DATE NOT NULL,
  status            TEXT NOT NULL DEFAULT 'confirmed',
  duration_override INT,  -- overrides course.days for this specific booking
  notes             TEXT,
  created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at        TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- 12. BOOKING RESOURCE ALLOCATIONS — per-instance copy of the schedule template.
--     Created when a booking is confirmed. Used for clash detection.
CREATE TABLE public.booking_resource_allocations (
  id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  booking_id    UUID NOT NULL REFERENCES course_bookings(id) ON DELETE CASCADE,
  venue_id      UUID NOT NULL REFERENCES venues(id),
  day_number    INT NOT NULL,
  session       TEXT NOT NULL,
  resource_type TEXT NOT NULL,
  resource_id   UUID NOT NULL,
  created_at    TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- 13. LOCATION RESOURCE BLOCKS — admin-imposed blocks on specific resources
CREATE TABLE public.location_resource_blocks (
  id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  venue_id      UUID NOT NULL REFERENCES venues(id),
  resource_type TEXT NOT NULL,
  resource_id   UUID NOT NULL,
  blocked_date  DATE NOT NULL,
  reason        TEXT,
  blocked_by    UUID,
  created_at    TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (resource_id, blocked_date)
);

-- 14. COURSE ORDERS — customer purchases
CREATE TABLE public.course_orders (
  id                       UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  course_id                UUID NOT NULL REFERENCES courses(id),
  trainer_id               UUID REFERENCES trainers(id),
  venue_id                 UUID REFERENCES venues(id),
  start_date               DATE NOT NULL,
  customer_name            TEXT NOT NULL,
  customer_email           TEXT NOT NULL,
  num_delegates            INT NOT NULL DEFAULT 1,
  price_cents              INT NOT NULL,
  status                   TEXT NOT NULL DEFAULT 'pending',
  payment_method           TEXT NOT NULL DEFAULT 'stripe',
  stripe_payment_intent_id TEXT,
  company_id               UUID REFERENCES training_companies(id),
  user_id                  UUID,
  created_at               TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at               TIMESTAMPTZ NOT NULL DEFAULT now()
);`;

const phpAvailability = `<?php
/**
 * ============================================================
 * COURSE AVAILABILITY ENGINE — PHP Implementation
 * ============================================================
 *
 * This class replicates the availability logic from the React
 * hook useCourseAvailability.ts for traditional PHP/MySQL or
 * PHP/PostgreSQL server-side applications.
 *
 * Dependencies: PDO (database), Carbon (dates) or DateTime
 */

namespace App\\Services;

use Carbon\\Carbon;
use Carbon\\CarbonImmutable;
use PDO;

class CourseAvailabilityService
{
    private PDO $db;

    /**
     * UK Bank Holidays — maintain this array annually.
     * In production, fetch from https://www.gov.uk/bank-holidays.json
     */
    private array $bankHolidays = [
        '2026-01-01', '2026-04-03', '2026-04-06', '2026-05-04',
        '2026-05-25', '2026-08-31', '2026-12-25', '2026-12-28',
        '2027-01-01', '2027-03-26', '2027-03-29', '2027-05-03',
        '2027-05-31', '2027-08-30', '2027-12-27', '2027-12-28',
    ];

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    // ──────────────────────────────────────────────────
    // 1. PUBLIC ENTRY POINT — Is a date available?
    // ──────────────────────────────────────────────────

    /**
     * Check if a course can be booked starting on \$startDate.
     *
     * @param string \$courseId   UUID of the course
     * @param string \$startDate  'Y-m-d' format
     * @return bool
     */
    public function isDateAvailable(string \$courseId, string \$startDate): bool
    {
        \$date = CarbonImmutable::parse(\$startDate);

        // Rule 1: No past dates
        if (\$date->lt(Carbon::today())) return false;

        // Rule 2: No weekends
        if (\$date->isWeekend()) return false;

        // Rule 3: No bank holidays
        if (in_array(\$startDate, \$this->bankHolidays)) return false;

        // Rule 4: Get course details
        \$course = \$this->getCourse(\$courseId);
        if (!\\$course || \\$course['category'] === 'E-Learning') return false;

        // Rule 5: Get trainer assignments for this course
        \$assignments = \$this->getCourseTrainers(\$courseId);
        if (empty(\$assignments)) return false;

        // Rule 6: At least ONE assignment must pass ALL checks
        foreach (\$assignments as \$assignment) {
            \$trainerId = \$assignment['trainer_id'];
            \$venueId   = \$assignment['venue_id'];

            // Check A: Trainer available for entire course duration
            if (!\\$this->isTrainerAvailableForCourse(\$trainerId, \$date, \$course['days'])) {
                continue;
            }

            // Check B: Resources not blocked or clashed
            if (!\\$this->areResourcesAvailable(\$courseId, \$date, \$course['days'])) {
                continue;
            }

            // All checks passed for this assignment
            return true;
        }

        return false;
    }

    // ──────────────────────────────────────────────────
    // 2. TRAINER AVAILABILITY
    // ──────────────────────────────────────────────────

    /**
     * Check if a trainer is available for every working day
     * of the course duration starting from \$startDate.
     */
    private function isTrainerAvailableForCourse(
        string \$trainerId,
        CarbonImmutable \$startDate,
        int \$courseDays
    ): bool {
        \$trainer = \$this->getTrainer(\$trainerId);
        \$mode    = \$trainer['availability_mode'] ?? 'weekly';
        \$workingDays = \$this->getWorkingDays(\$startDate, \$courseDays);

        foreach (\$workingDays as \$dayStr) {
            \$day = CarbonImmutable::parse(\$dayStr);

            // Step 1: Is the trainer working this day?
            if (\$mode === 'specific_dates') {
                if (!\\$this->isTrainerAvailableSpecific(\$trainerId, \$dayStr)) return false;
            } else {
                if (!\\$this->isTrainerAvailableWeekly(\$trainerId, \$day, \$dayStr)) return false;
            }

            // Step 2: Is the trainer already booked?
            if (\$this->isTrainerBookedOnDate(\$trainerId, \$dayStr)) return false;
        }

        return true;
    }

    /**
     * WEEKLY MODE: Trainer is available if:
     *  - Day is not a weekend
     *  - Day is not a bank holiday
     *  - No non-working override exists for this date
     *  - Weekly pattern says available (or no pattern = default available)
     */
    private function isTrainerAvailableWeekly(
        string \$trainerId,
        CarbonImmutable \$date,
        string \$dateStr
    ): bool {
        // Bank holidays
        if (in_array(\$dateStr, \$this->bankHolidays)) return false;

        // Weekends
        if (\$date->isWeekend()) return false;

        // Non-working override (e.g., holiday, sick day)
        \$stmt = \$this->db->prepare(
            "SELECT 1 FROM trainer_availability_overrides
             WHERE trainer_id = ? AND override_date = ? AND is_available = false
             LIMIT 1"
        );
        \$stmt->execute([\$trainerId, \$dateStr]);
        if (\$stmt->fetch()) return false;

        // Weekly pattern check (day_of_week: 0=Sun, 6=Sat — PHP Carbon convention)
        \$dow = \$date->dayOfWeek; // 0=Sun, 1=Mon ... 6=Sat
        \$stmt = \$this->db->prepare(
            "SELECT is_available FROM trainer_availability_weekly
             WHERE trainer_id = ? AND day_of_week = ?
             LIMIT 1"
        );
        \$stmt->execute([\$trainerId, \$dow]);
        \$row = \$stmt->fetch(PDO::FETCH_ASSOC);
        if (\$row && !\$row['is_available']) return false;

        return true;
    }

    /**
     * SPECIFIC DATES MODE: Trainer is ONLY available on dates
     * explicitly marked in the overrides table with is_available=true.
     */
    private function isTrainerAvailableSpecific(string \$trainerId, string \$dateStr): bool
    {
        if (in_array(\$dateStr, \$this->bankHolidays)) return false;

        \$stmt = \$this->db->prepare(
            "SELECT 1 FROM trainer_availability_overrides
             WHERE trainer_id = ? AND override_date = ? AND is_available = true
             LIMIT 1"
        );
        \$stmt->execute([\$trainerId, \$dateStr]);
        return (bool) \$stmt->fetch();
    }

    /**
     * Check if a trainer already has a confirmed booking that
     * occupies any of the same calendar dates.
     */
    private function isTrainerBookedOnDate(string \$trainerId, string \$dateStr): bool
    {
        \$stmt = \$this->db->prepare(
            "SELECT cb.start_date, c.days
             FROM course_bookings cb
             JOIN courses c ON c.id = cb.course_id
             WHERE cb.trainer_id = ? AND cb.status = 'confirmed'"
        );
        \$stmt->execute([\$trainerId]);
        \$bookings = \$stmt->fetchAll(PDO::FETCH_ASSOC);

        foreach (\$bookings as \$booking) {
            \$occupiedDates = \$this->getWorkingDays(
                CarbonImmutable::parse(\$booking['start_date']),
                (int) \$booking['days']
            );
            if (in_array(\$dateStr, \$occupiedDates)) return true;
        }

        return false;
    }

    // ──────────────────────────────────────────────────
    // 3. RESOURCE AVAILABILITY (Rooms & Yards)
    // ──────────────────────────────────────────────────

    /**
     * Check that every resource required by the course schedule
     * template is available on the corresponding calendar date.
     *
     * Two checks per resource per day:
     *  A) Not admin-blocked (location_resource_blocks)
     *  B) Not already allocated to another booking (booking_resource_allocations)
     *     — unless the resource is a "shared" yard
     */
    private function areResourcesAvailable(
        string \$courseId,
        CarbonImmutable \$startDate,
        int \$courseDays
    ): bool {
        // Get the course venue schedule template
        \$stmt = \$this->db->prepare(
            "SELECT * FROM course_venue_schedules WHERE course_id = ?"
        );
        \$stmt->execute([\$courseId]);
        \$schedule = \$stmt->fetchAll(PDO::FETCH_ASSOC);

        if (empty(\$schedule)) return true; // No resource requirements

        \$workingDays = \$this->getWorkingDays(\$startDate, \$courseDays);

        // Pre-fetch shared yard IDs
        \$yardIds = array_unique(array_map(
            fn(\$s) => \$s['resource_id'],
            array_filter(\$schedule, fn(\$s) => \$s['resource_type'] === 'yard')
        ));
        \$sharedYardIds = [];
        if (!empty(\$yardIds)) {
            \$placeholders = implode(',', array_fill(0, count(\$yardIds), '?'));
            \$stmt = \$this->db->prepare(
                "SELECT id FROM venue_yards WHERE id IN (\$placeholders) AND shared = true"
            );
            \$stmt->execute(array_values(\$yardIds));
            \$sharedYardIds = array_column(\$stmt->fetchAll(PDO::FETCH_ASSOC), 'id');
        }

        foreach (\$schedule as \$entry) {
            \$calendarDate = \$workingDays[\$entry['day_number'] - 1] ?? null;
            if (!\$calendarDate) continue;

            // Check A: Admin block
            if (\$this->isResourceBlocked(\$entry['resource_id'], \$calendarDate)) {
                return false;
            }

            // Check B: Clash (skip for shared yards)
            if (!in_array(\$entry['resource_id'], \$sharedYardIds)) {
                if (\$this->isResourceClashed(
                    \$entry['resource_id'],
                    \$calendarDate,
                    \$entry['session']
                )) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Is a resource blocked by an admin on this date?
     */
    private function isResourceBlocked(string \$resourceId, string \$dateStr): bool
    {
        \$stmt = \$this->db->prepare(
            "SELECT 1 FROM location_resource_blocks
             WHERE resource_id = ? AND blocked_date = ?
             LIMIT 1"
        );
        \$stmt->execute([\$resourceId, \$dateStr]);
        return (bool) \$stmt->fetch();
    }

    /**
     * Is a resource already allocated to another confirmed booking
     * on the same calendar date and session (AM/PM/Full Day)?
     *
     * This performs "session-level" clash detection:
     *  - Two bookings using Room A on Monday AM = CLASH
     *  - One on Monday AM + one on Monday PM   = OK
     */
    private function isResourceClashed(
        string \$resourceId,
        string \$calendarDate,
        string \$session
    ): bool {
        // Get all allocations for this resource
        \$stmt = \$this->db->prepare(
            "SELECT bra.day_number, bra.session,
                    cb.start_date, c.days
             FROM booking_resource_allocations bra
             JOIN course_bookings cb ON cb.id = bra.booking_id
             JOIN courses c ON c.id = cb.course_id
             WHERE bra.resource_id = ?
               AND cb.status = 'confirmed'"
        );
        \$stmt->execute([\$resourceId]);
        \$allocations = \$stmt->fetchAll(PDO::FETCH_ASSOC);

        foreach (\$allocations as \$alloc) {
            if (\$alloc['session'] !== \$session) continue;

            // Map allocation's day_number to actual calendar date
            \$allocWorkingDays = \$this->getWorkingDays(
                CarbonImmutable::parse(\$alloc['start_date']),
                (int) \$alloc['days']
            );
            \$allocCalendarDate = \$allocWorkingDays[\$alloc['day_number'] - 1] ?? null;

            if (\$allocCalendarDate === \$calendarDate) return true;
        }

        return false;
    }

    // ──────────────────────────────────────────────────
    // 4. VENUE-LOCKING (Trainer can't be at two venues)
    // ──────────────────────────────────────────────────

    /**
     * If a trainer already has an active order at Venue A on a
     * given date, they cannot be booked at Venue B on the same date.
     * This prevents physical impossibility in multi-venue setups.
     */
    public function getAvailableVenuesForDate(
        string \$courseId,
        string \$startDate
    ): array {
        \$date = CarbonImmutable::parse(\$startDate);
        \$course = \$this->getCourse(\$courseId);
        \$assignments = \$this->getCourseTrainers(\$courseId);
        \$results = [];

        // Build venue-lock map from existing orders
        \$venueLocks = \$this->buildVenueLockMap(\$date);

        foreach (\$assignments as \$a) {
            if (!\\$this->isTrainerAvailableForCourse(\$a['trainer_id'], \$date, \$course['days'])) continue;
            if (!\\$this->areResourcesAvailable(\$courseId, \$date, \$course['days'])) continue;

            // Venue-lock check
            \$lockedVenue = \$venueLocks[\$a['trainer_id']] ?? null;
            if (\$lockedVenue && \$a['venue_id'] && \$lockedVenue !== \$a['venue_id']) continue;

            \$results[] = [
                'trainer_id' => \$a['trainer_id'],
                'venue_id'   => \$a['venue_id'],
            ];
        }

        return \$results;
    }

    private function buildVenueLockMap(CarbonImmutable \$date): array
    {
        \$dateStr = \$date->format('Y-m-d');
        \$stmt = \$this->db->prepare(
            "SELECT co.trainer_id, co.venue_id, co.start_date, c.days
             FROM course_orders co
             JOIN courses c ON c.id = co.course_id
             WHERE co.status IN ('pending', 'paid', 'confirmed')
               AND co.trainer_id IS NOT NULL
               AND co.venue_id IS NOT NULL"
        );
        \$stmt->execute();
        \$orders = \$stmt->fetchAll(PDO::FETCH_ASSOC);

        \$locks = [];
        foreach (\$orders as \$order) {
            \$occupied = \$this->getWorkingDays(
                CarbonImmutable::parse(\$order['start_date']),
                (int) \$order['days']
            );
            if (in_array(\$dateStr, \$occupied)) {
                \$locks[\$order['trainer_id']] = \$order['venue_id'];
            }
        }
        return \$locks;
    }

    // ──────────────────────────────────────────────────
    // 5. BOOKING LIFECYCLE — Resource Allocation
    // ──────────────────────────────────────────────────

    /**
     * When a booking is confirmed, copy the course schedule template
     * into booking_resource_allocations for per-instance tracking.
     */
    public function allocateBookingResources(string \$bookingId, string \$courseId): void
    {
        \$stmt = \$this->db->prepare(
            "SELECT * FROM course_venue_schedules WHERE course_id = ?"
        );
        \$stmt->execute([\$courseId]);
        \$template = \$stmt->fetchAll(PDO::FETCH_ASSOC);

        \$insert = \$this->db->prepare(
            "INSERT INTO booking_resource_allocations
             (booking_id, venue_id, day_number, session, resource_type, resource_id)
             VALUES (?, ?, ?, ?, ?, ?)"
        );

        foreach (\$template as \$entry) {
            \$insert->execute([
                \$bookingId,
                \$entry['venue_id'],
                \$entry['day_number'],
                \$entry['session'],
                \$entry['resource_type'],
                \$entry['resource_id'],
            ]);
        }
    }

    /**
     * When an order is fully refunded or cancelled, release the
     * booking and its resource allocations.
     */
    public function releaseBookingResources(
        string \$courseId,
        string \$startDate,
        string \$trainerId
    ): void {
        // Find the matching booking
        \$stmt = \$this->db->prepare(
            "SELECT id FROM course_bookings
             WHERE course_id = ? AND start_date = ? AND trainer_id = ?
               AND status = 'confirmed'"
        );
        \$stmt->execute([\$courseId, \$startDate, \$trainerId]);
        \$bookings = \$stmt->fetchAll(PDO::FETCH_ASSOC);

        // Check if other active orders share this slot
        \$stmt = \$this->db->prepare(
            "SELECT COUNT(*) as cnt FROM course_orders
             WHERE course_id = ? AND start_date = ? AND trainer_id = ?
               AND status IN ('paid', 'confirmed')"
        );
        \$stmt->execute([\$courseId, \$startDate, \$trainerId]);
        \$count = (int) \$stmt->fetch(PDO::FETCH_ASSOC)['cnt'];

        // Only release if this is the last active order
        if (\$count <= 1) {
            foreach (\$bookings as \$booking) {
                \$this->db->prepare(
                    "DELETE FROM booking_resource_allocations WHERE booking_id = ?"
                )->execute([\$booking['id']]);

                \$this->db->prepare(
                    "UPDATE course_bookings SET status = 'cancelled' WHERE id = ?"
                )->execute([\$booking['id']]);
            }
        }
    }

    // ──────────────────────────────────────────────────
    // HELPERS
    // ──────────────────────────────────────────────────

    /**
     * Calculate the N working days (Mon-Fri, excluding bank holidays)
     * starting from a given date. Returns array of 'Y-m-d' strings.
     *
     * Example: getWorkingDays('2026-04-20', 3) might return:
     *   ['2026-04-20', '2026-04-21', '2026-04-22']
     * But if 2026-04-21 is a bank holiday:
     *   ['2026-04-20', '2026-04-22', '2026-04-23']
     */
    private function getWorkingDays(CarbonImmutable \$start, int \$numDays): array
    {
        \$days = [];
        \$current = \$start;
        \$count = 0;
        \$safety = 0;

        while (\$count < \$numDays && \$safety < 365) {
            \$dateStr = \$current->format('Y-m-d');
            if (!\$current->isWeekend() && !in_array(\$dateStr, \$this->bankHolidays)) {
                \$days[] = \$dateStr;
                \$count++;
            }
            \$current = \$current->addDay();
            \$safety++;
        }

        return \$days;
    }

    private function getCourse(string \$id): ?array
    {
        \$stmt = \$this->db->prepare("SELECT * FROM courses WHERE id = ?");
        \$stmt->execute([\$id]);
        return \$stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }

    private function getTrainer(string \$id): ?array
    {
        \$stmt = \$this->db->prepare("SELECT * FROM trainers WHERE id = ?");
        \$stmt->execute([\$id]);
        return \$stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }

    private function getCourseTrainers(string \$courseId): array
    {
        \$stmt = \$this->db->prepare(
            "SELECT ct.trainer_id, ct.venue_id, v.name as venue_name
             FROM course_trainers ct
             LEFT JOIN venues v ON v.id = ct.venue_id
             WHERE ct.course_id = ?"
        );
        \$stmt->execute([\$courseId]);
        return \$stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}`;

const phpCheckout = `<?php
/**
 * ============================================================
 * CHECKOUT VALIDATION — Capacity & Race-Condition Handling
 * ============================================================
 */

namespace App\\Services;

use PDO;
use Carbon\\CarbonImmutable;

class CheckoutService
{
    private PDO \$db;
    private CourseAvailabilityService \$availability;

    public function __construct(PDO \$db, CourseAvailabilityService \$availability)
    {
        \$this->db = \$db;
        \$this->availability = \$availability;
    }

    /**
     * Validate a booking before payment processing.
     *
     * @throws \\RuntimeException if validation fails
     */
    public function validateBooking(
        string \$courseId,
        string \$startDate,
        string \$trainerId,
        int    \$numDelegates
    ): void {
        // 1. Check date is still available
        if (!\\$this->availability->isDateAvailable(\$courseId, \$startDate)) {
            throw new \\RuntimeException('Selected date is no longer available');
        }

        // 2. Check course capacity (global 8-delegate limit)
        \$course = \$this->getCourse(\$courseId);
        \$capacity = \$course['capacity'] ?? 8;

        \$stmt = \$this->db->prepare(
            "SELECT COALESCE(SUM(num_delegates), 0) as booked
             FROM course_orders
             WHERE course_id = ? AND start_date = ? AND trainer_id = ?
               AND status IN ('pending', 'paid', 'confirmed')"
        );
        \$stmt->execute([\$courseId, \$startDate, \$trainerId]);
        \$booked = (int) \$stmt->fetch(PDO::FETCH_ASSOC)['booked'];

        if (\$booked + \$numDelegates > \$capacity) {
            throw new \\RuntimeException(
                "Only " . (\$capacity - \$booked) . " places remaining"
            );
        }

        // 3. Check room/yard capacity per session
        \$this->validateResourceCapacity(\$courseId, \$startDate, \$numDelegates);
    }

    /**
     * After payment succeeds, create the booking and allocate resources.
     * Uses a database transaction to prevent race conditions.
     */
    public function completeBooking(
        string \$orderId,
        string \$courseId,
        string \$trainerId,
        string \$startDate
    ): void {
        \$this->db->beginTransaction();

        try {
            // Check if booking already exists for this slot
            \$stmt = \$this->db->prepare(
                "SELECT id FROM course_bookings
                 WHERE course_id = ? AND start_date = ? AND trainer_id = ?
                   AND status = 'confirmed'
                 LIMIT 1"
            );
            \$stmt->execute([\$courseId, \$startDate, \$trainerId]);
            \$existing = \$stmt->fetch(PDO::FETCH_ASSOC);

            if (!\$existing) {
                // Create new booking
                \$bookingId = \$this->createBooking(\$courseId, \$trainerId, \$startDate);

                // Copy schedule template → resource allocations
                \$this->availability->allocateBookingResources(\$bookingId, \$courseId);
            }

            // Update order status
            \$this->db->prepare(
                "UPDATE course_orders SET status = 'paid' WHERE id = ?"
            )->execute([\$orderId]);

            \$this->db->commit();
        } catch (\\Exception \$e) {
            \$this->db->rollBack();
            throw \$e;
        }
    }

    /**
     * SERVER-SIDE RACE CONDITION HANDLING
     *
     * If payment succeeds but the trainer has become unavailable
     * (another booking was confirmed between page load and payment),
     * automatically refund the payment and mark the order as cancelled.
     */
    public function handlePostPaymentValidation(
        string \$orderId,
        string \$courseId,
        string \$startDate,
        string \$trainerId,
        string \$stripePaymentIntentId
    ): bool {
        if (!\\$this->availability->isDateAvailable(\$courseId, \$startDate)) {
            // Auto-refund via Stripe
            \$this->processAutoRefund(\$stripePaymentIntentId);

            // Mark order as cancelled
            \$this->db->prepare(
                "UPDATE course_orders
                 SET status = 'cancelled',
                     cancelled_at = NOW(),
                     refund_reason = 'Auto-refund: trainer unavailable after payment'
                 WHERE id = ?"
            )->execute([\$orderId]);

            return false; // Booking failed
        }

        return true; // Booking succeeded
    }

    // ... helper methods
    private function getCourse(string \$id): array { /* ... */ }
    private function createBooking(string \$courseId, string \$trainerId, string \$date): string { /* ... */ }
    private function validateResourceCapacity(string \$courseId, string \$date, int \$delegates): void { /* ... */ }
    private function processAutoRefund(string \$paymentIntentId): void { /* ... */ }
}`;

const jsonStructures = `{
  "___SECTION___": "1. COURSE TRAINER ASSIGNMENT",
  "___NOTE___": "Links a trainer to a course with an optional default venue",
  "course_trainers": [
    {
      "id": "ct-001",
      "course_id": "c-nrswa-5day",
      "trainer_id": "t-michael-moran",
      "venue_id": "v-widnes-centre"
    },
    {
      "id": "ct-002",
      "course_id": "c-nrswa-5day",
      "trainer_id": "t-alan-watson",
      "venue_id": "v-manchester-hub"
    }
  ],

  "___SECTION_2___": "2. COURSE VENUE SCHEDULE (Template)",
  "___NOTE_2___": "Defines WHAT resources the course needs on each day/session. This is the blueprint — not tied to any specific booking.",
  "course_venue_schedules": [
    {
      "course_id": "c-nrswa-5day",
      "venue_id": "v-widnes-centre",
      "day_number": 1,
      "session": "AM",
      "resource_type": "room",
      "resource_id": "room-a"
    },
    {
      "course_id": "c-nrswa-5day",
      "venue_id": "v-widnes-centre",
      "day_number": 1,
      "session": "PM",
      "resource_type": "yard",
      "resource_id": "yard-1"
    },
    {
      "course_id": "c-nrswa-5day",
      "venue_id": "v-widnes-centre",
      "day_number": 2,
      "session": "Full Day",
      "resource_type": "yard",
      "resource_id": "yard-1"
    }
  ],

  "___SECTION_3___": "3. BOOKING RESOURCE ALLOCATIONS (Instance)",
  "___NOTE_3___": "When booking B-001 is confirmed, the template above is COPIED here. This is the per-booking instance used for clash detection.",
  "booking_resource_allocations": [
    {
      "booking_id": "b-001",
      "venue_id": "v-widnes-centre",
      "day_number": 1,
      "session": "AM",
      "resource_type": "room",
      "resource_id": "room-a"
    },
    {
      "booking_id": "b-001",
      "venue_id": "v-widnes-centre",
      "day_number": 1,
      "session": "PM",
      "resource_type": "yard",
      "resource_id": "yard-1"
    }
  ],

  "___SECTION_4___": "4. TRAINER AVAILABILITY (Weekly Mode)",
  "trainer_availability_weekly": [
    { "trainer_id": "t-michael-moran", "day_of_week": 1, "is_available": true },
    { "trainer_id": "t-michael-moran", "day_of_week": 2, "is_available": true },
    { "trainer_id": "t-michael-moran", "day_of_week": 3, "is_available": true },
    { "trainer_id": "t-michael-moran", "day_of_week": 4, "is_available": true },
    { "trainer_id": "t-michael-moran", "day_of_week": 5, "is_available": true },
    { "trainer_id": "t-michael-moran", "day_of_week": 6, "is_available": false }
  ],

  "___SECTION_5___": "5. LOCATION RESOURCE BLOCKS",
  "___NOTE_5___": "Admin-imposed blocks that override availability regardless of other checks.",
  "location_resource_blocks": [
    {
      "venue_id": "v-widnes-centre",
      "resource_type": "room",
      "resource_id": "room-a",
      "blocked_date": "2026-05-18",
      "reason": "Maintenance — ceiling repair"
    }
  ],

  "___SECTION_6___": "6. AVAILABILITY CHECK RESULT",
  "___NOTE_6___": "The combined output: which start dates are bookable.",
  "availability_result": {
    "course_id": "c-nrswa-5day",
    "checked_dates": [
      { "date": "2026-05-18", "available": false, "reason": "Room A blocked on Day 1" },
      { "date": "2026-05-19", "available": false, "reason": "Trainer booked on Day 3 (Wed)" },
      { "date": "2026-05-26", "available": true,  "trainer": "t-michael-moran", "venue": "v-widnes-centre" }
    ]
  }
}`;

const cssStyles = `/* ============================================================
 * AVAILABILITY CALENDAR — CSS for traditional HTML builds
 * ============================================================ */

:root {
  --cal-available: #22c55e;       /* Green — bookable date */
  --cal-unavailable: #e5e7eb;     /* Grey — not bookable */
  --cal-blocked: #ef4444;         /* Red — admin-blocked */
  --cal-selected: #3b82f6;        /* Blue — user selection */
  --cal-past: #f3f4f6;            /* Light grey — past dates */
  --cal-weekend: #fafafa;         /* Off-white — weekend cells */
  --cal-today: #f59e0b;           /* Amber — current date ring */
}

/* Calendar grid */
.availability-calendar {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  max-width: 400px;
  font-family: system-ui, -apple-system, sans-serif;
}

.cal-header {
  text-align: center;
  font-weight: 600;
  font-size: 0.75rem;
  text-transform: uppercase;
  color: #6b7280;
  padding: 8px 0;
}

.cal-day {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  font-size: 0.875rem;
  cursor: default;
  transition: all 0.15s ease;
  position: relative;
}

.cal-day--available {
  background: color-mix(in srgb, var(--cal-available) 15%, white);
  color: #15803d;
  cursor: pointer;
  font-weight: 600;
}
.cal-day--available:hover {
  background: var(--cal-available);
  color: white;
  transform: scale(1.05);
}

.cal-day--unavailable {
  background: var(--cal-unavailable);
  color: #9ca3af;
}

.cal-day--blocked {
  background: color-mix(in srgb, var(--cal-blocked) 10%, white);
  color: #dc2626;
}
.cal-day--blocked::after {
  content: '';
  position: absolute;
  inset: 4px;
  border: 2px dashed #fca5a5;
  border-radius: 6px;
}

.cal-day--selected {
  background: var(--cal-selected);
  color: white;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.4);
}

.cal-day--past {
  background: var(--cal-past);
  color: #d1d5db;
}

.cal-day--weekend {
  background: var(--cal-weekend);
  color: #d1d5db;
}

.cal-day--today {
  box-shadow: inset 0 0 0 2px var(--cal-today);
}

/* Venue selector shown after date selection */
.venue-selector {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  margin-top: 16px;
}

.venue-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.venue-option:hover {
  border-color: var(--cal-selected);
  background: color-mix(in srgb, var(--cal-selected) 5%, white);
}
.venue-option--selected {
  border-color: var(--cal-selected);
  background: color-mix(in srgb, var(--cal-selected) 10%, white);
}

/* Resource clash indicator on calendar */
.cal-day--clash-warning {
  position: relative;
}
.cal-day--clash-warning::before {
  content: '!';
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: 0.625rem;
  font-weight: 700;
  color: #f59e0b;
}`;

const masterFlowDiagram = `graph TD
    START[Customer visits Course Detail Page] --> LOAD[Load Course Data]
    LOAD --> FETCH_TRAINERS[Fetch course_trainers for this course]
    FETCH_TRAINERS --> FETCH_AVAIL[Fetch trainer weekly/override availability]
    FETCH_AVAIL --> FETCH_BOOKINGS[Fetch existing course_bookings]
    FETCH_BOOKINGS --> FETCH_SCHEDULE[Fetch course_venue_schedules template]
    FETCH_SCHEDULE --> FETCH_ALLOC[Fetch booking_resource_allocations]
    FETCH_ALLOC --> FETCH_BLOCKS[Fetch location_resource_blocks]
    FETCH_BLOCKS --> RENDER[Render Calendar - 90 day window]

    RENDER --> DATE_CHECK{For each date}
    DATE_CHECK --> PAST{Past date?}
    PAST -->|Yes| GREY[Grey - Skip]
    PAST -->|No| WEEKEND{Weekend?}
    WEEKEND -->|Yes| GREY
    WEEKEND -->|No| BANK{Bank Holiday?}
    BANK -->|Yes| GREY
    BANK -->|No| TRAINER_LOOP{For each trainer assignment}

    TRAINER_LOOP --> MODE{Availability Mode?}
    MODE -->|Weekly| WEEKLY_CHECK[Check weekly pattern + overrides]
    MODE -->|Specific| SPECIFIC_CHECK[Check explicit available dates]
    WEEKLY_CHECK --> BOOKED{Trainer already booked?}
    SPECIFIC_CHECK --> BOOKED
    BOOKED -->|Yes| NEXT_TRAINER[Try next trainer]
    BOOKED -->|No| RESOURCE_CHECK[Check ALL resource requirements]

    RESOURCE_CHECK --> BLOCKED{Any resource admin-blocked?}
    BLOCKED -->|Yes| NEXT_TRAINER
    BLOCKED -->|No| CLASHED{Any resource clashed? Session-level}
    CLASHED -->|Yes| SHARED{Is it a shared yard?}
    SHARED -->|Yes| CAPACITY{Capacity OK?}
    SHARED -->|No| NEXT_TRAINER
    CLASHED -->|No| VENUE_LOCK{Trainer locked to different venue?}
    CAPACITY -->|Yes| VENUE_LOCK
    CAPACITY -->|No| NEXT_TRAINER

    VENUE_LOCK -->|Yes| NEXT_TRAINER
    VENUE_LOCK -->|No| GREEN[Date is AVAILABLE]
    NEXT_TRAINER -->|More trainers| TRAINER_LOOP
    NEXT_TRAINER -->|No more| GREY`;

const bookingLifecycleDiagram = `graph TD
    A[Customer selects available date] --> B[Select venue from available options]
    B --> C[Enter delegate details]
    C --> D{Payment method?}
    D -->|Stripe| E[Create Stripe PaymentIntent]
    D -->|Company Credit| F[Validate credit balance]
    E --> G[Process card payment]
    F --> H[Deduct credit]
    G --> I{Payment succeeded?}
    H --> I
    I -->|No| J[Show error]
    I -->|Yes| K[payment-webhook fires]

    K --> L{Trainer still available? Race condition check}
    L -->|No| M[Auto-refund via Stripe]
    M --> N[Cancel order]
    L -->|Yes| O{Booking exists for slot?}
    O -->|Yes| P[Reuse existing booking]
    O -->|No| Q[Create course_booking]
    Q --> R[Copy course_venue_schedules to booking_resource_allocations]

    P --> S[Update order status to paid]
    R --> S
    S --> T[Send confirmation email]
    T --> U[Schedule joining instructions]
    U --> V[Send pre-course forms to delegates]`;

const resourceDataModel = `erDiagram
    courses ||--o{ course_trainers : "assigned to"
    trainers ||--o{ course_trainers : "teaches"
    venues ||--o{ course_trainers : "default venue"
    courses ||--o{ course_venue_schedules : "resource template"
    venues ||--o{ course_venue_schedules : "at venue"
    venues ||--o{ venue_rooms : "contains"
    venues ||--o{ venue_yards : "contains"
    courses ||--o{ course_bookings : "booked as"
    trainers ||--o{ course_bookings : "delivers"
    course_bookings ||--o{ booking_resource_allocations : "occupies"
    venues ||--o{ booking_resource_allocations : "at venue"
    venues ||--o{ location_resource_blocks : "blocked at"
    trainers ||--o{ trainer_availability_weekly : "weekly pattern"
    trainers ||--o{ trainer_availability_overrides : "date overrides"
    courses ||--o{ course_orders : "ordered"
    trainers ||--o{ course_orders : "trainer for"
    venues ||--o{ course_orders : "venue for"
    course_orders ||--o{ booking_delegates : "delegates"`;

const trainerAvailDiagram = `graph TD
    A[Check Trainer Availability for Date] --> B{What mode?}
    B -->|weekly| C[Get day_of_week from date]
    B -->|specific_dates| D[Look up overrides where is_available=true]

    C --> E{Is weekend?}
    E -->|Yes| F[NOT AVAILABLE]
    E -->|No| G{Is bank holiday?}
    G -->|Yes| F
    G -->|No| H{Has non-working override?}
    H -->|Yes| F
    H -->|No| I{Weekly pattern says available?}
    I -->|No entry| J[Default: AVAILABLE]
    I -->|is_available=false| F
    I -->|is_available=true| J

    D --> K{Date in override list?}
    K -->|No| F
    K -->|Yes| L{Is bank holiday?}
    L -->|Yes| F
    L -->|No| J

    J --> M{Already booked on this date?}
    M -->|Yes| F
    M -->|No| N[TRAINER AVAILABLE]`;

const workingDaysDiagram = `graph LR
    A[Start Date: Mon 20 Apr] --> B[Day 1: Mon 20 Apr - Working Day]
    B --> C[Day 2: Tue 21 Apr - Working Day]
    C --> D[Day 3: Wed 22 Apr - Working Day]
    D --> E[Thu 23 Apr - BANK HOLIDAY - Skip]
    E --> F[Day 4: Fri 24 Apr - Working Day]
    F --> G[Sat 25 Apr - WEEKEND - Skip]
    G --> H[Sun 26 Apr - WEEKEND - Skip]
    H --> I[Day 5: Mon 27 Apr - Working Day]`;

/* ─────────────────── COMPONENT ─────────────────── */

const CodeBlock = ({ code, lang, title }: { code: string; lang: string; title: string }) => (
  <div className="relative group">
    <div className="flex items-center justify-between bg-muted/50 px-4 py-2 rounded-t-lg border border-border border-b-0">
      <div className="flex items-center gap-2">
        <Badge variant="outline" className="text-xs">{lang}</Badge>
        <span className="text-sm font-medium text-foreground">{title}</span>
      </div>
      <Button variant="ghost" size="sm" onClick={() => copy(code)} className="opacity-0 group-hover:opacity-100 transition-opacity">
        <Copy className="h-3.5 w-3.5 mr-1" /> Copy
      </Button>
    </div>
    <pre className="bg-muted/30 p-4 rounded-b-lg border border-border overflow-x-auto text-xs leading-relaxed">
      <code>{code}</code>
    </pre>
  </div>
);

const ResourceManagementDocsPage = () => {
  const [activeSection, setActiveSection] = useState("overview");

  const sections = [
    { key: "overview", label: "System Overview", icon: BookOpen },
    { key: "database", label: "Database Schema", icon: Database },
    { key: "availability", label: "Availability Engine (PHP)", icon: FileCode },
    { key: "checkout", label: "Checkout & Booking (PHP)", icon: Code2 },
    { key: "json", label: "JSON Data Structures", icon: LayoutGrid },
    { key: "css", label: "Calendar CSS", icon: Palette },
    { key: "diagrams", label: "Flow Diagrams", icon: GitBranch },
  ];

  return (
    <div className="flex h-screen bg-background">
      {/* Sidebar */}
      <aside className="hidden lg:flex w-[260px] border-r border-border flex-col shrink-0">
        <div className="p-4 border-b border-border">
          <h1 className="text-base font-bold text-foreground">Resource Management</h1>
          <p className="text-xs text-muted-foreground mt-1">Developer Reference Guide</p>
        </div>
        <ScrollArea className="flex-1">
          <div className="p-3 space-y-1">
            {sections.map((s) => {
              const Icon = s.icon;
              return (
                <button
                  key={s.key}
                  onClick={() => setActiveSection(s.key)}
                  className={`w-full flex items-center gap-2 px-3 py-2 rounded-md text-sm transition-colors text-left ${
                    activeSection === s.key
                      ? "bg-primary/10 text-primary border-l-2 border-primary font-medium"
                      : "text-foreground hover:bg-muted"
                  }`}
                >
                  <Icon className="h-4 w-4 shrink-0" />
                  <span className="truncate">{s.label}</span>
                </button>
              );
            })}
          </div>
        </ScrollArea>
      </aside>

      {/* Main */}
      <div className="flex-1 flex flex-col min-w-0">
        <header className="h-14 border-b border-border flex items-center gap-3 px-4 shrink-0">
          <div className="flex items-center gap-2 flex-1 min-w-0">
            <Badge variant="secondary" className="text-xs shrink-0">INTERNAL</Badge>
            <span className="font-semibold text-foreground truncate">
              Resource Management — Full Logic Reference
            </span>
          </div>
        </header>

        <ScrollArea className="flex-1">
          <div className="p-4 md:p-8 max-w-5xl mx-auto space-y-8">

            {/* ─── OVERVIEW ─── */}
            {activeSection === "overview" && (
              <>
                <div>
                  <h2 className="text-2xl font-bold text-foreground mb-2">System Overview</h2>
                  <p className="text-muted-foreground leading-relaxed mb-6">
                    This document describes the complete resource management logic used to determine
                    course availability, handle bookings, and manage physical resources (trainers,
                    rooms, yards) across multiple venues. It is designed to enable a developer to
                    replicate this system in any traditional web framework (Django, Rails, etc.).
                  </p>
                </div>

                <Card>
                  <CardHeader><CardTitle className="text-lg">Core Concepts</CardTitle></CardHeader>
                  <CardContent className="space-y-4">
                    <div className="grid md:grid-cols-2 gap-4">
                      {[
                        { title: "Template → Instance Pattern", desc: "Course venue schedules define WHAT resources are needed (the template). When a booking is confirmed, this template is copied into booking_resource_allocations (the instance). Clash detection uses instances, not templates." },
                        { title: "Session-Level Granularity", desc: "Resources are allocated per session (AM/PM/Full Day), not per day. Two courses can share a room if one uses it AM and another PM." },
                        { title: "Dual Availability Modes", desc: "Trainers operate in either 'weekly' mode (Mon-Fri recurring pattern with day-off overrides) or 'specific_dates' mode (only available on explicitly selected dates)." },
                        { title: "Shared vs Exclusive Resources", desc: "Yards can be marked as 'shared', meaning multiple courses can use them simultaneously. Capacity is still enforced, but exclusive clash detection is skipped." },
                        { title: "Venue-Locking", desc: "If a trainer has an active booking at Venue A, they cannot be booked at Venue B on the same date. This prevents physical impossibility." },
                        { title: "Working Days Calculation", desc: "Course days skip weekends and UK bank holidays. A 5-day course starting Monday might span 7+ calendar days if there's a bank holiday mid-week." },
                        { title: "Multi-Venue Courses", desc: "A single course can span multiple venues (e.g., Day 1 at Location A, Day 2 at Location B). The schedule template supports per-day venue assignments." },
                        { title: "Race Condition Handling", desc: "If a trainer becomes unavailable between page load and payment completion, the payment webhook automatically refunds via Stripe and cancels the order." },
                      ].map((c, i) => (
                        <div key={i} className="p-4 rounded-lg border border-border">
                          <h4 className="font-semibold text-foreground text-sm mb-1">{c.title}</h4>
                          <p className="text-xs text-muted-foreground leading-relaxed">{c.desc}</p>
                        </div>
                      ))}
                    </div>
                  </CardContent>
                </Card>

                <Card>
                  <CardHeader><CardTitle className="text-lg">Entity Relationship Model</CardTitle></CardHeader>
                  <CardContent>
                    <MermaidDiagram chart={resourceDataModel} id="erd" />
                  </CardContent>
                </Card>

                <Card>
                  <CardHeader><CardTitle className="text-lg">Availability Decision Flow</CardTitle></CardHeader>
                  <CardContent>
                    <MermaidDiagram chart={masterFlowDiagram} id="master-flow" />
                  </CardContent>
                </Card>
              </>
            )}

            {/* ─── DATABASE ─── */}
            {activeSection === "database" && (
              <>
                <h2 className="text-2xl font-bold text-foreground mb-2">Database Schema</h2>
                <p className="text-muted-foreground mb-6">
                  Complete PostgreSQL DDL for all 14 tables involved in resource management.
                  Adapt column types for MySQL (e.g., UUID → CHAR(36), TIMESTAMPTZ → DATETIME).
                </p>
                <CodeBlock code={sqlSchema} lang="SQL" title="Full Schema — 14 Tables" />
              </>
            )}

            {/* ─── AVAILABILITY ENGINE ─── */}
            {activeSection === "availability" && (
              <>
                <h2 className="text-2xl font-bold text-foreground mb-2">Availability Engine</h2>
                <p className="text-muted-foreground mb-6">
                  Complete PHP service class implementing the availability check logic.
                  This is the server-side equivalent of the React <code className="text-primary">useCourseAvailability</code> hook.
                </p>

                <Card className="mb-6">
                  <CardHeader><CardTitle className="text-sm">Decision Sequence</CardTitle></CardHeader>
                  <CardContent>
                    <div className="flex flex-wrap gap-2 items-center text-xs">
                      {[
                        "Past date?", "Weekend?", "Bank holiday?",
                        "Trainer available? (weekly/specific)", "Trainer already booked?",
                        "Resources admin-blocked?", "Resources clashed? (session-level)",
                        "Shared yard? → capacity check", "Venue-locked?"
                      ].map((step, i) => (
                        <div key={i} className="flex items-center gap-1">
                          <Badge variant="outline" className="text-xs">{i + 1}</Badge>
                          <span className="text-foreground">{step}</span>
                          {i < 8 && <ChevronRight className="h-3 w-3 text-muted-foreground" />}
                        </div>
                      ))}
                    </div>
                  </CardContent>
                </Card>

                <CodeBlock code={phpAvailability} lang="PHP" title="CourseAvailabilityService.php — Full Implementation" />

                <div className="mt-6">
                  <Card>
                    <CardHeader><CardTitle className="text-sm">Trainer Availability Decision Tree</CardTitle></CardHeader>
                    <CardContent>
                      <MermaidDiagram chart={trainerAvailDiagram} id="trainer-avail" />
                    </CardContent>
                  </Card>
                </div>

                <div className="mt-6">
                  <Card>
                    <CardHeader><CardTitle className="text-sm">Working Days Calculation Example</CardTitle></CardHeader>
                    <CardContent>
                      <MermaidDiagram chart={workingDaysDiagram} id="working-days" />
                      <p className="text-xs text-muted-foreground mt-3">
                        A 5-day course starting Mon 20 Apr spans 8 calendar days due to a bank holiday on Thu 23 Apr and the weekend.
                      </p>
                    </CardContent>
                  </Card>
                </div>
              </>
            )}

            {/* ─── CHECKOUT ─── */}
            {activeSection === "checkout" && (
              <>
                <h2 className="text-2xl font-bold text-foreground mb-2">Checkout & Booking Lifecycle</h2>
                <p className="text-muted-foreground mb-6">
                  Handles payment processing, capacity validation, booking creation, resource allocation,
                  and race-condition recovery.
                </p>

                <Card className="mb-6">
                  <CardHeader><CardTitle className="text-sm">Booking Lifecycle Flow</CardTitle></CardHeader>
                  <CardContent>
                    <MermaidDiagram chart={bookingLifecycleDiagram} id="booking-lifecycle" />
                  </CardContent>
                </Card>

                <CodeBlock code={phpCheckout} lang="PHP" title="CheckoutService.php — Validation, Booking & Race Conditions" />
              </>
            )}

            {/* ─── JSON ─── */}
            {activeSection === "json" && (
              <>
                <h2 className="text-2xl font-bold text-foreground mb-2">JSON Data Structures</h2>
                <p className="text-muted-foreground mb-6">
                  Example data showing how records relate to each other across the system.
                  Use these as test fixtures when building the availability engine.
                </p>
                <CodeBlock code={jsonStructures} lang="JSON" title="Sample Data — All Key Entities" />
              </>
            )}

            {/* ─── CSS ─── */}
            {activeSection === "css" && (
              <>
                <h2 className="text-2xl font-bold text-foreground mb-2">Calendar UI Styles</h2>
                <p className="text-muted-foreground mb-6">
                  Drop-in CSS for rendering an availability calendar in a traditional HTML/CSS build.
                  Uses CSS custom properties for easy theming.
                </p>
                <CodeBlock code={cssStyles} lang="CSS" title="availability-calendar.css" />

                <Card className="mt-6">
                  <CardHeader><CardTitle className="text-sm">Calendar Date States</CardTitle></CardHeader>
                  <CardContent>
                    <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
                      {[
                        { cls: "bg-green-100 text-green-700 border-green-300", label: "Available", desc: "Date is bookable" },
                        { cls: "bg-gray-100 text-gray-400 border-gray-200", label: "Unavailable", desc: "No trainer/resource" },
                        { cls: "bg-red-50 text-red-600 border-red-200", label: "Blocked", desc: "Admin resource block" },
                        { cls: "bg-blue-500 text-white border-blue-600", label: "Selected", desc: "User's chosen date" },
                      ].map((s, i) => (
                        <div key={i} className={`p-3 rounded-lg border ${s.cls} text-center`}>
                          <div className="font-semibold text-sm">{s.label}</div>
                          <div className="text-xs mt-1 opacity-80">{s.desc}</div>
                        </div>
                      ))}
                    </div>
                  </CardContent>
                </Card>
              </>
            )}

            {/* ─── DIAGRAMS ─── */}
            {activeSection === "diagrams" && (
              <>
                <h2 className="text-2xl font-bold text-foreground mb-2">System Flow Diagrams</h2>
                <p className="text-muted-foreground mb-6">
                  All key decision and data flows visualised. Click to expand each diagram.
                </p>

                <Accordion type="multiple" defaultValue={["master-flow"]}>
                  {[
                    { id: "master-flow", title: "Master Availability Check Flow", desc: "The complete decision tree from page load to date availability", chart: masterFlowDiagram },
                    { id: "booking-flow", title: "Booking Lifecycle", desc: "Payment → validation → resource allocation → notifications", chart: bookingLifecycleDiagram },
                    { id: "trainer-flow", title: "Trainer Availability Decision Tree", desc: "Weekly vs specific dates mode with all exclusion rules", chart: trainerAvailDiagram },
                    { id: "erd-flow", title: "Entity Relationship Diagram", desc: "How all 14 tables connect", chart: resourceDataModel },
                    { id: "working-flow", title: "Working Days Calculation", desc: "How course days map to calendar days", chart: workingDaysDiagram },
                  ].map((d) => (
                    <AccordionItem key={d.id} value={d.id}>
                      <AccordionTrigger className="hover:no-underline">
                        <div className="text-left">
                          <div className="font-medium text-sm">{d.title}</div>
                          <div className="text-xs text-muted-foreground">{d.desc}</div>
                        </div>
                      </AccordionTrigger>
                      <AccordionContent>
                        <MermaidDiagram chart={d.chart} id={d.id} />
                      </AccordionContent>
                    </AccordionItem>
                  ))}
                </Accordion>
              </>
            )}

          </div>
        </ScrollArea>
      </div>
    </div>
  );
};

export default ResourceManagementDocsPage;
