import { useEffect, useState, useCallback, useMemo } from 'react';
import { useParams, useLocation, useNavigate } from 'react-router-dom';
import { pb } from '../lib/pocketbase';
import { computeROTotals, roServiceTotal } from '../lib/totals';
import type { RepairOrder, ROService, ServiceItem, ROEvent, ROFinancialAuditEntry } from '../types';
import { getStatusConfig } from '../lib/status';
import { formatCurrency, formatDateTime, formatElapsed } from '../lib/format';
import { useToast } from '../components/ui/Toast';
import LoadingSpinner from '../components/ui/LoadingSpinner';
import {
  X, Wrench, Search, Plus, Check, History,
  FileText, Printer, Download, Mail, Phone, Ban, Clock3,
  ArrowLeft, AlertTriangle, DollarSign, Tag,
  Package, Trash2, Loader2, Layers, Save, BellRing
} from 'lucide-react';
import {
  readEvents, appendROEvent, readPromisedOverride,
  setPromisedOverride, isVoided, setVoided,
  clockRunning, clockElapsedMinutes, clockStart, clockStop
} from '../lib/roEvents';
import { openEmailDraft, openSmsDraft } from '../lib/contactLinks';
import { downloadROPDF, printROPDF } from '../lib/roPdf';
import { useSettings } from '../store/settings';
import { logError } from '../lib/userMessages';
import { parseRepairOrderServices, syncAssignmentsForROServices } from '../lib/technicianData';
import { formatServiceTextFields } from '../lib/dataFormatting';
import { spellCheckProps } from '../lib/spellcheck';

type TabId = 'details' | 'services' | 'financial' | 'history' | 'timeline';

const TABS: { id: TabId; label: string; icon: typeof Wrench }[] = [
  { id: 'details', label: 'Details', icon: FileText },
  { id: 'services', label: 'Services', icon: Wrench },
  { id: 'financial', label: 'Financial', icon: DollarSign },
  { id: 'history', label: 'History', icon: History },
  { id: 'timeline', label: 'Timeline', icon: Clock3 },
];

/* ── Shared helpers (inlined from ServiceCatalog) ─── */

function getServiceLaborPrice(service: Pick<ServiceItem, 'laborHours' | 'laborRate'>): number {
  return (Number(service.laborHours) || 0) * (Number(service.laborRate) || 0);
}

function getServicePricingMode(service: Pick<ServiceItem, 'laborHours' | 'laborRate' | 'partsCost'>): 'full' | 'split' {
  return getServiceLaborPrice(service) > 0 || (Number(service.partsCost) || 0) > 0 ? 'split' : 'full';
}

interface ServiceFormState {
  name: string;
  category: string;
  description: string;
  pricingMode: 'full' | 'split';
  fullPrice: number;
  laborPrice: number;
  partsPrice: number;
}

function createEmptyServiceForm(): ServiceFormState {
  return {
    name: '',
    category: '',
    description: '',
    pricingMode: 'full',
    fullPrice: 0,
    laborPrice: 0,
    partsPrice: 0,
  };
}

/* ── Helpers ───────────────────────────────────────── */

function formatDueDateTime(ro: RepairOrder): string {
  const override = readPromisedOverride(ro);
  if (override) return formatDateTime(override);
  if (ro.promisedTime) return formatDateTime(ro.promisedTime);
  if (ro.writeupTime) {
    const d = new Date(ro.writeupTime);
    d.setHours(d.getHours() + 4);
    return formatDateTime(d.toISOString());
  }
  return '—';
}

function formatTimeRemaining(ro: RepairOrder, now: number): string {
  const override = readPromisedOverride(ro);
  const target = override || ro.promisedTime || (ro.writeupTime ? new Date(new Date(ro.writeupTime).getTime() + 4 * 60 * 60 * 1000).toISOString() : '');
  if (!target) return '—';
  const diff = new Date(target).getTime() - now;
  if (diff <= 0) return 'Overdue';
  const hours = Math.floor(diff / 3600000);
  const minutes = Math.floor((diff % 3600000) / 60000);
  return `${hours}h ${minutes}m`;
}

function formatCompletedTime(ro: RepairOrder): string {
  return formatDateTime(ro.completedTime || ro.completedDate || '');
}

function getUrgencyClass(ro: RepairOrder, now: number): '' | 'warning' | 'urgent' {
  const override = readPromisedOverride(ro);
  const target = override || ro.promisedTime || (ro.writeupTime ? new Date(new Date(ro.writeupTime).getTime() + 4 * 60 * 60 * 1000).toISOString() : '');
  if (!target) return '';
  const diff = new Date(target).getTime() - now;
  if (diff < 0) return 'urgent';
  if (diff < 60 * 60 * 1000) return 'warning';
  return '';
}

function StatusBadge({ status, config }: { status: string; config: Record<string, { label: string; colors: string }> }) {
  const cfg = config[status as keyof typeof config] || { label: status, colors: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300' };
  return <span className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${cfg.colors}`}>{cfg.label}</span>;
}

function TimelineEntry({ ev }: { ev: ROEvent }) {
  const desc = (() => {
    switch (ev.type) {
      case 'created': return 'Repair order created';
      case 'edit': return 'Repair order edited';
      case 'status': return `Status changed: ${ev.data?.from} → ${ev.data?.to}`;
      case 'add_time': return `Added ${ev.data?.minutes} min (total: ${ev.data?.newTotal} min)`;
      case 'clock_start': return 'Technician clock started';
      case 'clock_stop': return `Technician clock stopped (${ev.data?.elapsed} min)`;
      case 'satisfaction': return `Customer rated ${ev.data?.rating}★`;
      case 'notify': return `Notified via ${ev.data?.channel} to ${ev.data?.to}`;
      case 'financial': return `Financial field updated: ${ev.data?.field}`;
      default: return ev.type;
    }
  })();
  return (
    <li className="flex items-start gap-3 py-2">
      <span className="mt-0.5 h-2 w-2 shrink-0 rounded-full bg-blue-400" />
      <div className="min-w-0 flex-1">
        <p className="text-sm text-gray-700 dark:text-gray-300">{desc}</p>
        <p className="text-xs text-gray-400">{formatDateTime(ev.at)}</p>
      </div>
    </li>
  );
}

/* ── AddTimeModal ──────────────────────────────────── */

function AddTimeModal({ open, initialMinutes, onCancel, onConfirm }: { open: boolean; initialMinutes: number; onCancel: () => void; onConfirm: (minutes: number) => void }) {
  const [minutes, setMinutes] = useState(initialMinutes);
  useEffect(() => { setMinutes(initialMinutes); }, [initialMinutes]);
  if (!open) return null;
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/30" onClick={onCancel}>
      <div className="w-80 rounded-xl bg-white p-6 shadow-xl dark:bg-gray-800" onClick={(e) => e.stopPropagation()}>
        <h3 className="text-sm font-semibold text-gray-900 dark:text-white">Add Time</h3>
        <p className="mt-1 text-xs text-gray-500 dark:text-gray-400">Extend the remaining time on this RO.</p>
        <input type="number" min={1} value={minutes} onChange={(e) => setMinutes(Number(e.target.value) || 1)} className="mt-3 w-full rounded border border-gray-300 bg-white px-3 py-2 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
        <div className="mt-4 flex justify-end gap-2">
          <button onClick={onCancel} className="rounded-lg border border-gray-300 px-3 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300">Cancel</button>
          <button onClick={() => onConfirm(minutes)} className="rounded-lg bg-blue-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-blue-700">Add</button>
        </div>
      </div>
    </div>
  );
}

/* ── Service Row (editable RO service row) ─────────── */

function PricingBadge({ mode }: { mode: 'full' | 'split' }) {
  if (mode === 'full') {
    return <span className="inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-[10px] font-medium text-green-700 dark:bg-green-900/30 dark:text-green-300">Full Price</span>;
  }
  return <span className="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 text-[10px] font-medium text-blue-700 dark:bg-blue-900/30 dark:text-blue-300">Split</span>;
}

function EditableServiceRow({ service, index, onChange, onRemove, defaultLaborRate = 145, spellCheck, lang }: {
  service: Partial<ROService>;
  index: number;
  onChange: (index: number, field: string, value: string | number | boolean) => void;
  onRemove: (index: number) => void;
  defaultLaborRate?: number;
  spellCheck?: boolean;
  lang?: string;
}) {
  const pricingMode = service.pricingMode || 'full';
  const isSplit = pricingMode === 'split';
  const total = roServiceTotal(service);
  const scOn = service.applyShopCharge !== false;
  return (
    <div className="rounded-lg border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-800/50">
      <div className="mb-2 flex items-center justify-between">
        <div className="flex items-center gap-2">
          <span className="text-xs font-medium text-gray-500 dark:text-gray-400">Service #{index + 1}</span>
          {/* Pricing mode toggle */}
          <div className="flex rounded-lg border border-gray-300 dark:border-gray-600 overflow-hidden text-xs">
            <button
              type="button"
              onClick={() => {
                if (isSplit) {
                  onChange(index, 'pricingMode', 'full');
                }
              }}
              className={`px-2 py-0.5 font-medium transition-colors ${
                !isSplit
                  ? 'bg-blue-600 text-white'
                  : 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-600'
              }`}
            >
              Full
            </button>
            <button
              type="button"
              onClick={() => {
                if (!isSplit) {
                  const flatTotal = service.total || total;
                  const rate = defaultLaborRate;
                  const hours = rate > 0 ? Math.round((flatTotal / rate) * 100) / 100 : 0;
                  onChange(index, 'pricingMode', 'split');
                  onChange(index, 'laborHours', hours);
                  onChange(index, 'laborRate', rate);
                  onChange(index, 'partsCost', 0);
                }
              }}
              className={`px-2 py-0.5 font-medium transition-colors ${
                isSplit
                  ? 'bg-blue-600 text-white'
                  : 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-600'
              }`}
            >
              Split
            </button>
          </div>
          <PricingBadge mode={pricingMode} />
          <button
            type="button"
            onClick={() => onChange(index, 'applyShopCharge', !scOn)}
            className={`rounded-md px-2 py-0.5 text-[11px] font-medium transition-colors ${
              scOn
                ? 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400'
                : 'bg-gray-100 text-gray-400 dark:bg-gray-700 dark:text-gray-500'
            }`}
            title={scOn ? 'Shop charge applies' : 'Shop charge excluded'}
          >
            {scOn ? 'Shop Charge On' : 'Shop Charge Off'}
          </button>
        </div>
        <button onClick={() => onRemove(index)} className="rounded p-1 text-gray-400 hover:bg-red-50 hover:text-red-500 dark:hover:bg-red-900/20">
          <Trash2 className="h-3.5 w-3.5" />
        </button>
      </div>
      <div className="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-5">
        <div className="sm:col-span-2 lg:col-span-1">
          <label className="block text-xs text-gray-500 dark:text-gray-400">Name</label>
          <input value={service.name || ''} onChange={(e) => onChange(index, 'name', e.target.value)} placeholder="Service name" className="mt-0.5 w-full rounded border border-gray-300 bg-white px-2 py-1.5 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
        </div>
        <div className="sm:col-span-2 lg:col-span-1">
          <label className="block text-xs text-gray-500 dark:text-gray-400">Description</label>
          <textarea value={service.description || ''} onChange={(e) => onChange(index, 'description', e.target.value)} placeholder="Description..." rows={1} spellCheck={spellCheck} lang={lang} className="mt-0.5 w-full rounded border border-gray-300 bg-white px-2 py-1.5 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
        </div>
        {pricingMode === 'full' ? (
          <>
            <div>
              <label className="block text-xs text-gray-500 dark:text-gray-400">Price ($)</label>
              <input type="number" min="0" step="0.01" value={service.total != null ? service.total : ''} onChange={(e) => onChange(index, 'total', parseFloat(e.target.value) || 0)} placeholder="0" className="mt-0.5 w-full rounded border border-gray-300 bg-white px-2 py-1.5 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
            </div>
            <div></div>
            <div></div>
            <div>
              <label className="block text-xs text-gray-500 dark:text-gray-400">Total</label>
              <div className="mt-0.5 flex h-[34px] items-center rounded border border-gray-200 bg-gray-100 px-2 text-sm font-medium text-gray-900 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100">
                {formatCurrency(total)}
              </div>
            </div>
          </>
        ) : (
          <>
            <div>
              <label className="block text-xs text-gray-500 dark:text-gray-400">Labor Hrs</label>
              <input type="number" min="0" step="0.1" value={service.laborHours || ''} onChange={(e) => onChange(index, 'laborHours', parseFloat(e.target.value) || 0)} placeholder="0" className="mt-0.5 w-full rounded border border-gray-300 bg-white px-2 py-1.5 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
            </div>
            <div>
              <label className="block text-xs text-gray-500 dark:text-gray-400">Rate/hr</label>
              <input type="number" min="0" step="1" value={service.laborRate || ''} onChange={(e) => onChange(index, 'laborRate', parseFloat(e.target.value) || 0)} placeholder="145" className="mt-0.5 w-full rounded border border-gray-300 bg-white px-2 py-1.5 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
            </div>
            <div>
              <label className="block text-xs text-gray-500 dark:text-gray-400">Parts $</label>
              <input type="number" min="0" step="0.01" value={service.partsCost || ''} onChange={(e) => onChange(index, 'partsCost', parseFloat(e.target.value) || 0)} placeholder="0" className="mt-0.5 w-full rounded border border-gray-300 bg-white px-2 py-1.5 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
            </div>
            <div>
              <label className="block text-xs text-gray-500 dark:text-gray-400">Total</label>
              <div className="mt-0.5 flex h-[34px] items-center rounded border border-gray-200 bg-gray-100 px-2 text-sm font-medium text-gray-900 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100">
                {formatCurrency(total)}
              </div>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

/* ── Form helper components (inlined) ────────────────── */

function FormField({ label, children }: { label: string; children: React.ReactNode }) {
  return <div className="space-y-1.5"><label className="block text-sm font-medium text-gray-700 dark:text-gray-300">{label}</label>{children}</div>;
}

function Input({ value, onChange, placeholder, type = 'text', icon }: { value: string | number; onChange: (value: string) => void; placeholder?: string; type?: string; icon?: React.ReactNode }) {
  return (
    <div className="relative">
      {icon && <div className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400">{icon}</div>}
      <input type={type} value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} className={`w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 focus:border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/20 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 ${icon ? 'pl-9' : ''}`} />
    </div>
  );
}

function Textarea({ value, onChange, placeholder, rows = 3, spellCheck, lang }: { value: string; onChange: (value: string) => void; placeholder?: string; rows?: number; spellCheck?: boolean; lang?: string }) {
  return (
    <textarea value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} rows={rows}
      spellCheck={spellCheck}
      lang={lang}
      className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 focus:border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/20 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100"
    />
  );
}

/* ── Main Modal Component ──────────────────────────── */

export default function RODetailModal() {
  const { id } = useParams<{ id: string }>();
  const location = useLocation();
  const navigate = useNavigate();
  const { showToast } = useToast();
  const settings = useSettings();
  const serviceTextSpellCheck = spellCheckProps(settings, settings.spellCheckServiceText);
  const internalNotesSpellCheck = spellCheckProps(settings, settings.spellCheckInternalNotes);
  const statusConfig = useMemo(() => getStatusConfig(settings), [settings]);

  const modalBackground = (location.state as { backgroundLocation?: unknown })?.backgroundLocation;
  const isModal = Boolean(modalBackground);

  const [ro, setRo] = useState<RepairOrder | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [activeTab, setActiveTab] = useState<TabId>('details');
  const [saving, setSaving] = useState(false);
  const [now, setNow] = useState(Date.now());

  // Details tab state
  const [showAddTimeModal, setShowAddTimeModal] = useState(false);
  const [showPromisedPicker, setShowPromisedPicker] = useState(false);
  const [promisedValue, setPromisedValue] = useState('');

  // Services tab state
  const [catalogServices, setCatalogServices] = useState<ServiceItem[]>([]);
  const [catalogSearch, setCatalogSearch] = useState('');
  const [showNewServiceForm, setShowNewServiceForm] = useState(false);
  const [newServiceForm, setNewServiceForm] = useState<ServiceFormState>(createEmptyServiceForm());
  const [localServices, setLocalServices] = useState<ROService[]>([]);
  const [servicesDirty, setServicesDirty] = useState(false);
  const [servicesSaved, setServicesSaved] = useState(false);

  // Reminder state
  const [showReminderForm, setShowReminderForm] = useState(false);
  const [reminderMileage, setReminderMileage] = useState('');
  const [reminderInterval, setReminderInterval] = useState('5000');
  const [reminderNotes, setReminderNotes] = useState('');
  const [savingReminder, setSavingReminder] = useState(false);

  // History tab state
  const [historyData, setHistoryData] = useState<{ type: 'ro' | 'quote'; id: string; date: string; title: string; vehicleInfo: string; total: number; status: string }[]>([]);
  const [historyLoading, setHistoryLoading] = useState(false);

  // Timeline
  const events = useMemo(() => (ro ? readEvents(ro) : []), [ro]);

  // Financial Audit Trail
  const [financialAuditEntries, setFinancialAuditEntries] = useState<ROFinancialAuditEntry[]>([]);
  const [financialAuditLoading, setFinancialAuditLoading] = useState(false);

  // Financial tab state
  const [finCpTotal, setFinCpTotal] = useState('');
  const [finCpCost, setFinCpCost] = useState('');
  const [finWarrTotal, setFinWarrTotal] = useState('');
  const [finWarrCost, setFinWarrCost] = useState('');
  const [finShopCharge, setFinShopCharge] = useState('');
  const [finSaving, setFinSaving] = useState(false);
  const [finSaved, setFinSaved] = useState(false);
  const [finSeeded, setFinSeeded] = useState(false);

  const userId = pb.authStore.model?.id;

  const closeModal = useCallback(() => {
    if (isModal) navigate(-1);
    else navigate('/repair-orders');
  }, [isModal, navigate]);

  useEffect(() => {
    if (!isModal) return;
    const handler = (e: KeyboardEvent) => {
      if (e.key === 'Escape') closeModal();
    };
    document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [isModal, closeModal]);

  // Live tick
  useEffect(() => {
    const tick = () => {
      const ts = Date.now();
      const mb = Math.floor(ts / 60000);
      setNow((prev) => (Math.floor(prev / 60000) === mb ? prev : ts));
    };
    const id = setInterval(tick, 30000);
    return () => clearInterval(id);
  }, []);

  // Fast tick when clock is running
  useEffect(() => {
    if (!ro || !clockRunning(ro)) return;
    const id = setInterval(() => setNow(Date.now()), 5000);
    return () => clearInterval(id);
  }, [ro]);

  const fetchRO = useCallback(async () => {
    if (!id || !userId) { setLoading(false); return; }
    setLoading(true);
    setError(null);
    try {
      const record = await pb.collection('repairOrders').getOne(id);
      const normalized = (() => {
        const item = record as Record<string, unknown>;
        let services: ROService[] = [];
        const raw = item.services;
        if (Array.isArray(raw)) services = raw as ROService[];
        else if (typeof raw === 'string' && raw.trim()) { try { services = JSON.parse(raw); } catch (err) { logError('Failed to parse RO services JSON', err); } }
        return { ...item, services } as unknown as RepairOrder;
      })();
      setRo(normalized);
      setLocalServices(normalized.services || []);
      setServicesDirty(false);
      setServicesSaved(false);
      setPromisedValue(readPromisedOverride(normalized) ? new Date(readPromisedOverride(normalized)!).toISOString().slice(0, 16) : '');
    } catch (err) {
      logError('Failed to load RO', err);
      setError('Repair order could not be loaded.');
    } finally {
      setLoading(false);
    }
  }, [id, userId]);

  const fetchCatalogServices = useCallback(async () => {
    if (!userId) return;
    try {
      const records = await pb.collection('services').getFullList({ filter: `userId="${userId}"`, sort: 'name' });
      setCatalogServices(records.map((r: Record<string, unknown>) => ({
        id: r.id as string,
        name: (r.name as string) || '',
        category: (r.category as string) || '',
        description: (r.explanation as string) || (r.description as string) || '',
        laborHours: Number(r.laborHours) || 0,
        laborRate: Number(r.laborRate) || 0,
        partsCost: Number(r.partsCost) || 0,
        price: Number(r.price) || 0,
        active: r.active !== false,
        created: (r.created as string) || '',
        updated: (r.updated as string) || '',
      })));
    } catch { /* non-critical */ }
  }, [userId]);

  useEffect(() => {
    fetchRO();
    fetchCatalogServices();
  }, [fetchRO, fetchCatalogServices]);

  const loadHistory = useCallback(async () => {
    if (!ro || !ro.vin || !ro.vin.trim()) {
      setHistoryData([]);
      return;
    }
    setHistoryLoading(true);
    const results: { type: 'ro' | 'quote'; id: string; date: string; title: string; vehicleInfo: string; total: number; status: string }[] = [];
    try {
      const roRecords = await pb.collection('repairOrders').getFullList({
        filter: `userId="${userId}" && vin="${ro.vin.trim()}"`,
        sort: '-created',
        fields: 'id,roNumber,customerName,vehicleInfo,vin,total,status,created',
      });
      for (const r of roRecords as Record<string, unknown>[]) {
        if (r.id === ro.id) continue;
        results.push({
          type: 'ro',
          id: r.id as string,
          date: (r.created as string) || '',
          title: `RO ${(r.roNumber as string) || (r.id as string)?.slice(0, 8) || ''}`,
          vehicleInfo: (r.vehicleInfo as string) || '',
          total: Number(r.total) || 0,
          status: (r.status as string) || '',
        });
      }
    } catch { /* ok */ }
    try {
      const qRecords = await pb.collection('quotes').getFullList({
        filter: `userId="${userId}" && vin="${ro.vin.trim()}"`,
        sort: '-created',
        fields: 'id,customerInfo,vehicleInfo,vin,total,status,created',
      });
      for (const q of qRecords as Record<string, unknown>[]) {
        const ci = q.customerInfo as Record<string, unknown> | undefined;
        results.push({
          type: 'quote',
          id: q.id as string,
          date: (q.created as string) || '',
          title: `Quote #${(q.id as string)?.slice(0, 8) || ''}`,
          vehicleInfo: (q.vehicleInfo as string) || (ci?.vehicleInfo as string) || '',
          total: Number(q.total) || 0,
          status: (q.status as string) || '',
        });
      }
    } catch { /* ok */ }
    results.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
    setHistoryData(results);
    setHistoryLoading(false);
  }, [ro, userId]);

  useEffect(() => {
    if (activeTab === 'history') loadHistory();
  }, [activeTab, loadHistory]);

  const loadFinancialAudit = useCallback(async () => {
    if (!ro) return;
    setFinancialAuditLoading(true);
    try {
      const records = await pb.collection('roFinancialAudit').getFullList({
        filter: `roId = '${ro.id}'`,
        sort: '-at',
      });
      setFinancialAuditEntries(records.map((r: Record<string, unknown>) => ({
        id: r.id as string,
        roId: r.roId as string,
        field: r.field as string,
        from: r.from,
        to: r.to,
        by: r.by as string,
        at: r.at as string,
        prevHash: r.prevHash as string,
        hash: r.hash as string,
      })));
    } catch {
      setFinancialAuditEntries([]);
    } finally {
      setFinancialAuditLoading(false);
    }
  }, [ro]);

  useEffect(() => {
    if (activeTab === 'timeline' && ro) loadFinancialAudit();
  }, [activeTab, ro, loadFinancialAudit]);

  // Pre-seed financial inputs from RO data when opening the Financial tab
  // for the first time (or when the RO changes).
  useEffect(() => {
    if (activeTab !== 'financial' || !ro || finSeeded) return;
    const f = (() => {
      const raw = ro.financial;
      if (typeof raw === 'string') { try { return JSON.parse(raw) as Record<string, any>; } catch { return {}; } }
      return (typeof raw === 'object' && raw ? raw : {}) as Record<string, any>;
    })();
    const existingCpTotal = f.grossTotal ?? f.cpTotal;
    const existingCpCost = f.grossCost ?? f.cpCost;
    const existingWarrTotal = f.warrTotal ?? f.whTotal;
    const existingWarrCost = f.warrCost ?? f.whCost;
    const existingShopCharge = f.shopCharge;
    const totals = computeROTotals({ services: ro.services || [], discount: ro.discount, settings });
    // CP Total is shop revenue before tax. Tax is pass-through and should not
    // be saved as customer-pay financial revenue.
    setFinCpTotal(existingCpTotal != null ? String(existingCpTotal) : totals.taxableBase.toFixed(2));
    setFinCpCost(existingCpCost != null ? String(existingCpCost) : '');
    setFinWarrTotal(existingWarrTotal != null ? String(existingWarrTotal) : '');
    setFinWarrCost(existingWarrCost != null ? String(existingWarrCost) : '');
    setFinShopCharge(existingShopCharge != null ? String(existingShopCharge) : totals.shopCharge.toFixed(2));
    setFinSeeded(true);
  }, [activeTab, ro, finSeeded, settings]);

  const voided = ro ? isVoided(ro) : false;
  const isActiveStatus = ro && ro.status !== 'completed' && ro.status !== 'final_close' && ro.status !== 'delivered' && !voided;
  const isCompletedStatus = ro && (ro.status === 'completed' || ro.status === 'final_close' || ro.status === 'delivered') && !voided;

  const urgency = ro && isActiveStatus ? getUrgencyClass(ro, now) : '';
  const clockActive = ro ? !!clockRunning(ro) : false;
  const clockElapsedMin = ro ? clockElapsedMinutes(ro) : 0;

  /* ── Handlers ────────────────────────────────────── */

  const handleStatusChange = async (status: RepairOrder['status']) => {
    if (!ro) return;
    const prevStatus = ro.status;
    let updatedServices: ROService[] | undefined;
    let updatedCompletedTime: string | undefined;
    if (status === 'completed') {
      updatedCompletedTime = new Date().toISOString();
      const allDone = (ro.services || []).every((s) => s.status === 'completed');
      if (!allDone) updatedServices = (ro.services || []).map((s) => ({ ...s, status: 'completed' as const }));
    } else if (['waiting_pickup', 'active', 'in_progress', 'waiting_parts'].includes(status)) {
      updatedCompletedTime = '';
    }

    setRo((prev) => prev ? { ...prev, status, completedTime: updatedCompletedTime, completedDate: updatedCompletedTime, services: updatedServices ?? prev.services } : prev);

    const update: Record<string, unknown> = { status };
    if (updatedCompletedTime !== undefined) update.completedTime = updatedCompletedTime;
    if (updatedServices) update.services = JSON.stringify(updatedServices);

    try {
      await pb.collection('repairOrders').update(ro.id, update);
      try {
        const linkedAppointment = await pb.collection('appointments').getFirstListItem(
          `repairOrderId = '${ro.id}' && userId = '${userId}'`
        );
        const as = status === 'completed' || status === 'final_close' || status === 'delivered' ? 'completed' : 'checked_in';
        if (linkedAppointment?.status !== as) await pb.collection('appointments').update(linkedAppointment.id, { status: as });
      } catch {}
      try { await appendROEvent(ro.id, 'status', { from: prevStatus, to: status }); } catch (err) { logError('Failed to append RO status event', err); showToast('Saved, but the timeline event could not be recorded.', 'error'); }
      showToast(`Status changed to ${status}.`, 'success');
    } catch {
      setRo((prev) => prev ? { ...prev, status: prevStatus, completedTime: undefined, completedDate: undefined } : prev);
      showToast('Failed to update status.', 'error');
    }
  };

  const handleClockStart = async () => {
    if (!ro) return;
    try { await clockStart(ro.id); setRo((prev) => prev ? { ...prev } : prev); showToast('Clock started.', 'success'); }
    catch { showToast('Failed to start clock.', 'error'); }
  };

  const handleClockStop = async () => {
    if (!ro) return;
    try { await clockStop(ro.id); setRo((prev) => prev ? { ...prev } : prev); showToast('Clock stopped.', 'success'); }
    catch { showToast('Failed to stop clock.', 'error'); }
  };

  const handleSaveReminder = async () => {
    if (!ro || !userId) return;
    const mileage = parseInt(reminderMileage) || 0;
    const interval = parseInt(reminderInterval) || 0;
    if (!mileage || !interval) { showToast('Please enter mileage and interval.', 'error'); return; }
    setSavingReminder(true);
    try {
      await pb.collection('reminders').create({
        customerId: ro.customerId || '',
        customerName: ro.customerName || '',
        vehicleInfo: ro.vehicleInfo || '',
        shopUserId: userId,
        mileageAtService: mileage,
        intervalMileage: interval,
        dueMileage: mileage + interval,
        notes: reminderNotes,
        active: true,
      });
      showToast('Reminder set successfully.', 'success');
      setShowReminderForm(false);
      setReminderNotes('');
    } catch {
      showToast('Failed to set reminder.', 'error');
    } finally {
      setSavingReminder(false);
    }
  };

  const handleSetPromisedOverride = async () => {
    if (!ro) return;
    try {
      await setPromisedOverride(ro.id, promisedValue ? new Date(promisedValue).toISOString() : null);
      setRo((prev) => prev ? { ...prev } : prev);
      showToast(promisedValue ? 'Promised time pinned.' : 'Override cleared.', 'success');
    } catch { showToast('Failed to set promised time.', 'error'); }
    setShowPromisedPicker(false);
  };

  const handleSetSatisfaction = async (rating: number) => {
    if (!ro) return;
    try {
      await pb.collection('repairOrders').update(ro.id, { satisfaction: rating });
      try { await appendROEvent(ro.id, 'satisfaction', { rating }); } catch (err) { logError('Failed to append RO satisfaction event', err); showToast('Saved, but the timeline event could not be recorded.', 'error'); }
      setRo((prev) => prev ? { ...prev, satisfaction: rating } : prev);
      showToast(`Rated ${rating}★.`, 'success');
    } catch { showToast('Failed to save rating.', 'error'); }
  };

  const handleNotifyCustomer = async (channel: 'email' | 'sms') => {
    if (!ro) return;
    const subject = `Your vehicle ${ro.vehicleInfo || ''} is ready for pickup — RO ${ro.roNumber || ''}`;
    const body = [
      `Hi ${ro.customerName || ''},`,
      '',
      `Your vehicle${ro.vehicleInfo ? ` (${ro.vehicleInfo})` : ''} is ready for pickup.`,
      `Repair Order: ${ro.roNumber || ''}`,
      ro.total ? `Invoice total: ${formatCurrency(ro.total)}` : '',
      '',
      'Please give us a call if you have any questions.',
    ].filter(Boolean).join('\n');
    if (channel === 'email') openEmailDraft(ro.customerEmail || '', subject, body);
    else openSmsDraft(ro.customerPhone || '', body);
    try { await appendROEvent(ro.id, 'notify', { channel, to: channel === 'email' ? ro.customerEmail : ro.customerPhone }); } catch (err) { logError('Failed to append RO notify event', err); showToast('Saved, but the timeline event could not be recorded.', 'error'); }
    showToast(`Opened ${channel === 'email' ? 'email' : 'SMS'} draft.`, 'success');
  };

  const handleVoid = async () => {
    if (!ro) return;
    if (!window.confirm(`Void RO ${ro.roNumber || ro.id.slice(0, 8)}?`)) return;
    try { await setVoided(ro.id, !voided); setRo((prev) => prev ? { ...prev } : prev); showToast(voided ? 'RO un-voided.' : 'RO voided.', 'success'); }
    catch { showToast('Failed to toggle void.', 'error'); }
  };

  const handleGenerateQuote = () => {
    if (!ro) return;
    const params = new URLSearchParams({
      fromRO: ro.id,
      name: ro.customerName || '',
      phone: ro.customerPhone || '',
      vehicleInfo: ro.vehicleInfo || '',
      vin: ro.vin || '',
      mileage: ro.mileage || '',
      roNumber: ro.roNumber || '',
      serviceAdvisor: ro.advisorName || '',
    });
    navigate(`/quote?${params.toString()}`);
  };

  const handlePrintRO = async () => {
    if (!ro) return;
    try { await printROPDF(ro, settings); } catch { showToast('Failed to open print window.', 'error'); }
  };

  const handleDownloadRO = async () => {
    if (!ro) return;
    try { await downloadROPDF(ro, settings); showToast('RO PDF downloaded.', 'success'); } catch { showToast('Failed to generate PDF.', 'error'); }
  };

  const handleAddTime = async (extraMinutes: number) => {
    if (!ro) return;
    const newDuration = (ro.estimatedDuration || 60) + extraMinutes;
    setRo((prev) => prev ? { ...prev, estimatedDuration: newDuration } : prev);
    try {
      await pb.collection('repairOrders').update(ro.id, { estimatedTime: (newDuration / 60).toFixed(1) });
      try { await appendROEvent(ro.id, 'add_time', { minutes: extraMinutes, newTotal: newDuration }); } catch (err) { logError('Failed to append RO add_time event', err); showToast('Saved, but the timeline event could not be recorded.', 'error'); }
    } catch {
      showToast('Failed to add time.', 'error');
      fetchRO();
    }
  };

  /* ── Financial tab handlers ─────────────────────────── */

  // Live computed values — warranty deducted from CP, shop charge deducted
  // from CP gross profit (per shop owner's business rules).
  const finCpTotalNum = parseFloat(finCpTotal) || 0;
  const finCpCostNum = parseFloat(finCpCost) || 0;
  const finWarrTotalNum = parseFloat(finWarrTotal) || 0;
  const finWarrCostNum = parseFloat(finWarrCost) || 0;
  const finShopChargeNum = parseFloat(finShopCharge) || 0;

  const cpNetTotal = Math.max(0, finCpTotalNum - finWarrTotalNum);
  const cpNetCost = Math.max(0, finCpCostNum - finWarrCostNum);
  const cpGrossProfit = cpNetTotal - cpNetCost - finShopChargeNum;
  const warrGrossProfit = finWarrTotalNum - finWarrCostNum;
  const overallGrossProfit = cpGrossProfit + warrGrossProfit;

  const handleSaveFinancial = async () => {
    if (!ro) return;
    setFinSaving(true);
    setFinSaved(false);
    try {
      // Read existing financial blob to preserve other keys (e.g. customerType)
      let existing: Record<string, any> = {};
      const raw = ro.financial;
      if (typeof raw === 'string') { try { existing = JSON.parse(raw); } catch { /* ignore */ } }
      else if (typeof raw === 'object' && raw) { existing = raw as Record<string, any>; }

      const financial = {
        ...existing,
        grossTotal: finCpTotalNum,
        grossCost: finCpCostNum,
        warrTotal: finWarrTotalNum,
        warrCost: finWarrCostNum,
        shopCharge: finShopChargeNum,
        cpProfit: cpGrossProfit,
        whProfit: warrGrossProfit,
        grossProfit: overallGrossProfit,
        totalAmount: finCpTotalNum + finWarrTotalNum,
        totalCost: finCpCostNum + finWarrCostNum,
        completedAt: existing.completedAt || new Date().toISOString(),
      };

      await pb.collection('repairOrders').update(ro.id, {
        financial: JSON.stringify(financial),
      });

      try {
        await appendROEvent(ro.id, 'financial', { field: 'grossProfit' });
      } catch (err) {
        logError('Failed to append RO financial event', err);
      }

      setRo((prev) => prev ? { ...prev, financial } : prev);
      setFinSaved(true);
      showToast('Financial data saved.', 'success');
      setTimeout(() => setFinSaved(false), 3000);
    } catch (err) {
      logError('Failed to save financial data', err);
      showToast('Failed to save financial data.', 'error');
    } finally {
      setFinSaving(false);
    }
  };

  /* ── Service handlers ────────────────────────────────── */

  const handleServiceChange = (index: number, field: string, value: string | number | boolean) => {
    setLocalServices((prev) => {
      const next = [...prev];
      next[index] = { ...next[index], [field]: value };
      return next;
    });
    setServicesDirty(true);
    setServicesSaved(false);
  };

  const handleRemoveService = (index: number) => {
    setLocalServices((prev) => prev.filter((_, i) => i !== index));
    setServicesDirty(true);
    setServicesSaved(false);
  };

  const handleAddService = () => {
    setLocalServices((prev) => [...prev, {
      id: `new-${Date.now()}`,
      name: '',
      description: '',
      laborHours: 0,
      laborRate: 0,
      partsCost: 0,
      total: 0,
      status: 'pending',
      technician: '',
      pricingMode: settings.defaultPricingMode,
      applyShopCharge: true,
    }]);
    setServicesDirty(true);
    setServicesSaved(false);
  };

  const handleAddCatalogService = (svc: ServiceItem) => {
    const laborPrice = getServiceLaborPrice(svc);
    const isSplit = getServicePricingMode(svc) === 'split';
    setLocalServices((prev) => [...prev, {
      id: `catalog-${svc.id}-${Date.now()}`,
      name: svc.name,
      description: svc.description,
      laborHours: isSplit ? 1 : 0,
      laborRate: isSplit ? laborPrice : 0,
      partsCost: isSplit ? svc.partsCost : 0,
      total: svc.price,
      status: 'pending',
      technician: '',
      pricingMode: isSplit ? 'split' : settings.defaultPricingMode,
      applyShopCharge: true,
    }]);
    setServicesDirty(true);
    setServicesSaved(false);
    showToast(`Added "${svc.name}" to RO.`, 'success');
  };

  const handleSaveServices = async () => {
    if (!ro) return;
    setSaving(true);
    try {
      const cleaned = localServices.map((s) => {
        const service = {
        id: s.id,
        name: s.name,
        description: s.description || '',
        laborHours: s.laborHours || 0,
        laborRate: s.laborRate || 0,
        partsCost: s.partsCost || 0,
        total: roServiceTotal(s),
        status: s.status || 'pending',
        technician: s.technician || '',
        pricingMode: s.pricingMode || 'full',
        applyShopCharge: s.applyShopCharge !== false,
        };
        return settings.applyServiceFormattingToROs ? formatServiceTextFields(service, settings) : service;
      });
      const payload = { services: JSON.stringify(cleaned) };
      await pb.collection('repairOrders').update(ro.id, payload);

      const savedRecord = await pb.collection('repairOrders').getOne(ro.id);
      const savedServices = parseRepairOrderServices((savedRecord as Record<string, unknown>).services);
      const savedIds = new Set(savedServices.map((s) => s.id));
      const missingSavedService = cleaned.some((s) => !savedIds.has(s.id));
      if (cleaned.length > 0 && (savedServices.length === 0 || missingSavedService)) {
        throw new Error('Saved repair order did not return the expected services.');
      }

      syncAssignmentsForROServices(ro.id, savedServices).catch((err) => {
        logError('Failed to sync technician assignments after service save', err);
      });
      try { await appendROEvent(ro.id, 'edit', {}); } catch (err) { logError('Failed to append RO edit event', err); showToast('Saved, but the timeline event could not be recorded.', 'error'); }
      setRo((prev) => prev ? { ...prev, services: savedServices } : prev);
      setLocalServices(savedServices);
      setServicesDirty(false);
      setServicesSaved(true);
      showToast('Services saved.', 'success');
      setTimeout(() => setServicesSaved(false), 3000);
    } catch (err) {
      logError('Failed to save services', err);
      showToast('Failed to save services.', 'error');
    } finally {
      setSaving(false);
    }
  };

  /* ── New catalog service in modal ────────────────── */

  const handleSaveNewService = async () => {
    if (!newServiceForm.name.trim()) { showToast('Service name is required.', 'error'); return; }
    if (!userId) return;
    const fullPrice = Number(newServiceForm.fullPrice) || 0;
    const laborPrice = Number(newServiceForm.laborPrice) || 0;
    const partsPrice = Number(newServiceForm.partsPrice) || 0;
    const isSplit = newServiceForm.pricingMode === 'split';
    const description = newServiceForm.description.trim();
    const data = formatServiceTextFields({
      name: newServiceForm.name.trim(),
      category: newServiceForm.category.trim(),
      description,
      explanation: description,
      laborHours: isSplit && laborPrice > 0 ? 1 : 0,
      laborRate: isSplit ? laborPrice : 0,
      partsCost: isSplit ? partsPrice : 0,
      price: isSplit ? laborPrice + partsPrice : fullPrice,
      active: true,
      userId,
    }, settings.applyServiceFormattingToCatalog ? settings : { ...settings, serviceNameFormat: 'preserve', serviceDescriptionFormat: 'preserve', serviceRecommendationFormat: 'preserve', serviceCategoryFormat: 'preserve', trimServiceText: true, addPeriodToServiceDescriptions: false });
    try {
      const created = await pb.collection('services').create(data) as Record<string, unknown>;
      const newSvc: ServiceItem = {
        id: created.id as string,
        name: data.name,
        category: data.category,
        description: data.description,
        laborHours: data.laborHours,
        laborRate: data.laborRate,
        partsCost: data.partsCost,
        price: data.price,
        active: true,
        created: '',
        updated: '',
      };
      setCatalogServices((prev) => [...prev, newSvc].sort((a, b) => a.name.localeCompare(b.name)));
      handleAddCatalogService(newSvc);
      setNewServiceForm(createEmptyServiceForm());
      setShowNewServiceForm(false);
      showToast('Service created and added to RO.', 'success');
    } catch {
      showToast('Failed to create service.', 'error');
    }
  };

  /* ── Render ──────────────────────────────────────── */

  if (loading) return <div className="flex min-h-[60vh] items-center justify-center"><LoadingSpinner text="Loading repair order..." /></div>;
  if (error || !ro) {
    const content = (
      <div className="flex flex-col items-center justify-center py-24">
        <AlertTriangle className="h-12 w-12 text-red-400" />
        <p className="mt-4 text-sm text-gray-500">{error || 'Repair order not found.'}</p>
        <button onClick={closeModal} className="mt-4 rounded-lg border border-gray-300 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300">Close</button>
      </div>
    );
    if (!isModal) return content;
    return (
      <div className="fixed inset-0 z-50 flex items-center justify-center bg-gray-950/45 backdrop-blur-sm">
        <div className="rounded-xl bg-white p-8 dark:bg-gray-900">{content}</div>
      </div>
    );
  }

  const totals = computeROTotals({ services: localServices, discount: ro.discount, settings });

  const filteredCatalog = catalogServices.filter((s) => {
    if (!catalogSearch.trim()) return true;
    const q = catalogSearch.toLowerCase();
    return s.name.toLowerCase().includes(q) || s.category.toLowerCase().includes(q) || s.description.toLowerCase().includes(q);
  });

  /* ── Tab content builders ────────────────────────── */

  const detailsContent = (
    <div className={voided ? 'opacity-60' : ''}>
      {voided && (
        <div className="mb-4 flex items-center gap-2 rounded-lg border border-red-300 bg-red-50 px-4 py-3 text-sm font-medium text-red-700 dark:border-red-700 dark:bg-red-900/20 dark:text-red-300">
          <Ban className="h-4 w-4" /> This repair order has been voided.
        </div>
      )}

      {/* Header */}
      <div className="mb-4 flex flex-wrap items-center gap-3">
        <div className="min-w-0 flex-1">
          <h2 className="text-lg font-semibold text-gray-900 dark:text-white">{ro.roNumber || `RO #${ro.id.slice(0, 8)}`}</h2>
          <p className="truncate text-sm text-gray-500 dark:text-gray-400">{ro.customerName} — {ro.vehicleInfo || 'No vehicle'}</p>
        </div>
        <div className="flex flex-wrap items-center gap-1.5">
          <button onClick={handlePrintRO} className="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"><Printer className="h-3.5 w-3.5" /> Print</button>
          <button onClick={handleDownloadRO} className="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"><Download className="h-3.5 w-3.5" /> PDF</button>
          <button onClick={handleGenerateQuote} className="inline-flex items-center gap-1.5 rounded-lg bg-green-600 px-3 py-1.5 text-xs font-medium text-white shadow-sm hover:bg-green-700"><FileText className="h-3.5 w-3.5" /> Generate Quote</button>
          <button onClick={() => { setReminderMileage(ro.mileage || ''); setReminderInterval('5000'); setReminderNotes(''); setShowReminderForm(!showReminderForm); }} className={`inline-flex items-center gap-1.5 rounded-lg border px-3 py-1.5 text-xs font-medium ${showReminderForm ? 'border-blue-300 bg-blue-50 text-blue-700 dark:border-blue-700 dark:bg-blue-900/20 dark:text-blue-300' : 'border-gray-300 bg-white text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700'}`}><BellRing className="h-3.5 w-3.5" /> Set Reminder</button>
        </div>
      </div>

      {/* Set Reminder inline form */}
      {showReminderForm && (
        <div className="mb-4 rounded-xl border border-blue-200 bg-blue-50 p-4 dark:border-blue-700 dark:bg-blue-900/20">
          <div className="mb-3 flex items-center justify-between">
            <h3 className="text-sm font-semibold text-blue-800 dark:text-blue-300">
              <BellRing className="mr-1.5 inline h-4 w-4" />
              Set Maintenance Reminder
            </h3>
            <button onClick={() => setShowReminderForm(false)} className="rounded p-1 text-blue-400 hover:text-blue-600 dark:hover:text-blue-300">
              <X className="h-4 w-4" />
            </button>
          </div>
          <div className="mb-3 text-xs text-blue-700 dark:text-blue-400">
            Customer: <strong>{ro.customerName}</strong> — Vehicle: <strong>{ro.vehicleInfo}</strong>
          </div>
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
            <div>
              <label className="block text-xs font-medium text-blue-700 dark:text-blue-300">Mileage at Service</label>
              <input
                type="number"
                value={reminderMileage}
                onChange={(e) => setReminderMileage(e.target.value)}
                placeholder={ro.mileage || 'Enter mileage'}
                className="mt-1 w-full rounded border border-blue-300 bg-white px-2 py-1.5 text-sm dark:border-blue-700 dark:bg-gray-800 dark:text-gray-100"
              />
            </div>
            <div>
              <label className="block text-xs font-medium text-blue-700 dark:text-blue-300">Interval (miles)</label>
              <input
                type="number"
                value={reminderInterval}
                onChange={(e) => setReminderInterval(e.target.value)}
                placeholder="5000"
                className="mt-1 w-full rounded border border-blue-300 bg-white px-2 py-1.5 text-sm dark:border-blue-700 dark:bg-gray-800 dark:text-gray-100"
              />
            </div>
            <div>
              <label className="block text-xs font-medium text-blue-700 dark:text-blue-300">Due Mileage (computed)</label>
              <div className="mt-1 flex h-[34px] items-center rounded border border-blue-200 bg-blue-100 px-2 text-sm font-medium text-blue-800 dark:border-blue-700 dark:bg-blue-900/40 dark:text-blue-300">
                {((parseInt(reminderMileage) || 0) + (parseInt(reminderInterval) || 0)).toLocaleString()}
              </div>
            </div>
          </div>
          <div className="mt-3">
            <label className="block text-xs font-medium text-blue-700 dark:text-blue-300">Notes (optional)</label>
            <textarea
              value={reminderNotes}
              onChange={(e) => setReminderNotes(e.target.value)}
              placeholder="e.g. Next oil change reminder"
              rows={2}
              {...internalNotesSpellCheck}
              className="mt-1 w-full rounded border border-blue-300 bg-white px-2 py-1.5 text-sm dark:border-blue-700 dark:bg-gray-800 dark:text-gray-100"
            />
          </div>
          <div className="mt-3 flex justify-end gap-2">
            <button
              onClick={() => setShowReminderForm(false)}
              className="rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300"
            >
              Cancel
            </button>
            <button
              onClick={handleSaveReminder}
              disabled={savingReminder}
              className="inline-flex items-center gap-1.5 rounded-lg bg-blue-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-blue-700 disabled:opacity-50"
            >
              {savingReminder ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <BellRing className="h-3.5 w-3.5" />}
              {savingReminder ? 'Saving...' : 'Save Reminder'}
            </button>
          </div>
        </div>
      )}

      {/* Info bar */}
      <div className="mb-4 rounded-xl bg-white p-4 ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
        <div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6">
          <div>
            <p className="text-xs font-medium text-gray-500 dark:text-gray-400">Customer</p>
            <p className="mt-1 text-sm font-medium text-gray-900 dark:text-gray-100">{ro.customerName || '—'}</p>
            {ro.customerPhone && <p className="text-xs text-gray-400">{ro.customerPhone}</p>}
          </div>
          <div>
            <p className="text-xs font-medium text-gray-500 dark:text-gray-400">Vehicle</p>
            <p className="mt-1 text-sm text-gray-900 dark:text-gray-100">{ro.vehicleInfo || '—'}</p>
            {ro.vin && <p className="text-xs text-gray-400">VIN: {ro.vin}</p>}
            {ro.mileage && <p className="text-xs text-gray-400">Mileage: {ro.mileage}</p>}
          </div>
          <div>
            <p className="text-xs font-medium text-gray-500 dark:text-gray-400">Status</p>
            <div className="mt-1"><StatusBadge status={voided ? 'voided' : (ro.status || '')} config={statusConfig} /></div>
          </div>
          <div>
            <p className="text-xs font-medium text-gray-500 dark:text-gray-400">Write-up</p>
            <p className="mt-1 text-sm text-gray-900 dark:text-gray-100">{formatDateTime(ro.writeupTime || ro.created)}</p>
          </div>
          <div>
            <p className="text-xs font-medium text-gray-500 dark:text-gray-400">Promised</p>
            <div className="mt-1 flex items-center gap-1.5">
              <span className="text-sm text-gray-900 dark:text-gray-100">{formatDueDateTime(ro)}</span>
              {isActiveStatus && (
                <button onClick={() => { setPromisedValue(readPromisedOverride(ro) ? new Date(readPromisedOverride(ro)!).toISOString().slice(0, 16) : ''); setShowPromisedPicker(true); }}
                  className="text-xs text-blue-600 hover:underline dark:text-blue-400">{readPromisedOverride(ro) ? 'clear' : 'pin'}</button>
              )}
            </div>
          </div>
          <div>
            <p className="text-xs font-medium text-gray-500 dark:text-gray-400">{isCompletedStatus ? 'Completed' : 'Time Remaining'}</p>
            <div className="mt-1 flex items-center gap-2">
              {isActiveStatus ? (
                <>
                  <span className={`text-sm ${urgency === 'urgent' ? 'font-semibold text-red-600 dark:text-red-400' : urgency === 'warning' ? 'font-medium text-amber-600 dark:text-amber-400' : 'text-gray-600 dark:text-gray-400'}`}>
                    {urgency === 'urgent' && <AlertTriangle className="mr-1 inline h-3.5 w-3.5 text-red-500" />}
                    {formatTimeRemaining(ro, now)}
                  </span>
                  <button onClick={() => setShowAddTimeModal(true)} className="inline-flex items-center gap-1 rounded border border-blue-300 bg-blue-50 px-2 py-0.5 text-xs font-medium text-blue-700 hover:bg-blue-100 dark:border-blue-700 dark:bg-blue-900/20 dark:text-blue-400">+ Add Time</button>
                </>
              ) : isCompletedStatus ? (
                <span className="text-sm text-gray-900 dark:text-gray-100">{formatCompletedTime(ro)}</span>
              ) : <span className="text-sm text-gray-400">—</span>}
            </div>
          </div>
        </div>
      </div>

      {/* Services summary */}
      <div className="mb-4 rounded-xl bg-white p-4 ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
        <div className="mb-3 flex flex-wrap items-center justify-between gap-2">
          <div>
            <h3 className="text-sm font-semibold text-gray-800 dark:text-gray-100">Services on this RO</h3>
            <p className="text-xs text-gray-500 dark:text-gray-400">
              {localServices.filter((s) => s.name?.trim()).length} service{localServices.filter((s) => s.name?.trim()).length === 1 ? '' : 's'} · {formatCurrency(totals.subtotal)} subtotal
            </p>
          </div>
          <button
            type="button"
            onClick={() => setActiveTab('services')}
            className="inline-flex items-center gap-1.5 rounded-lg border border-green-300 bg-green-50 px-3 py-1.5 text-xs font-medium text-green-700 hover:bg-green-100 dark:border-green-700 dark:bg-green-900/20 dark:text-green-300"
          >
            <Wrench className="h-3.5 w-3.5" /> Edit Services
          </button>
        </div>
        {localServices.filter((s) => s.name?.trim()).length > 0 ? (
          <div className="space-y-2">
            {localServices.filter((s) => s.name?.trim()).map((svc, i) => (
              <div key={`${svc.id}-${i}`} className="flex flex-wrap items-start justify-between gap-3 rounded-lg border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-700 dark:bg-gray-900/50">
                <div className="min-w-0 flex-1">
                  <div className="flex flex-wrap items-center gap-2">
                    <p className="truncate text-sm font-medium text-gray-900 dark:text-gray-100">{svc.name}</p>
                    <PricingBadge mode={svc.pricingMode || 'full'} />
                    <span className={`rounded-md px-2 py-0.5 text-[11px] font-medium ${svc.applyShopCharge !== false ? 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400' : 'bg-gray-100 text-gray-400 dark:bg-gray-700 dark:text-gray-500'}`}>
                      {svc.applyShopCharge !== false ? 'Shop Charge On' : 'Shop Charge Off'}
                    </span>
                  </div>
                  {svc.description && <p className="mt-1 line-clamp-2 text-xs text-gray-500 dark:text-gray-400">{svc.description}</p>}
                </div>
                <div className="text-right">
                  <p className="text-sm font-semibold text-gray-900 dark:text-gray-100">{formatCurrency(roServiceTotal(svc))}</p>
                  <p className="text-[11px] text-gray-400">Line total</p>
                </div>
              </div>
            ))}
          </div>
        ) : (
          <div className="rounded-lg border border-dashed border-gray-300 bg-gray-50 px-4 py-6 text-center dark:border-gray-700 dark:bg-gray-900/40">
            <p className="text-sm font-medium text-gray-600 dark:text-gray-300">No services have been added to this RO yet.</p>
            <button
              type="button"
              onClick={() => setActiveTab('services')}
              className="mt-3 inline-flex items-center gap-1.5 rounded-lg bg-green-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-green-700"
            >
              <Plus className="h-3.5 w-3.5" /> Add Services
            </button>
          </div>
        )}
      </div>

      {/* Promised-time override */}
      {showPromisedPicker && (
        <div className="mb-4 flex flex-wrap items-center gap-2 rounded-lg border border-orange-200 bg-orange-50 p-3 text-sm dark:border-orange-700 dark:bg-orange-900/20">
          <label className="text-xs font-medium text-orange-700 dark:text-orange-300">Pin ready-by time:</label>
          <input type="datetime-local" value={promisedValue} onChange={(e) => setPromisedValue(e.target.value)} className="rounded border border-orange-300 bg-white px-2 py-1 text-sm dark:border-orange-700 dark:bg-gray-800 dark:text-gray-100" />
          <button onClick={handleSetPromisedOverride} className="rounded bg-orange-600 px-3 py-1 text-xs font-medium text-white hover:bg-orange-700">Set</button>
          <button onClick={() => { handleSetPromisedOverride(); setShowPromisedPicker(false); }} className="rounded border border-gray-300 bg-white px-3 py-1 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300">Clear</button>
          <button onClick={() => setShowPromisedPicker(false)} className="rounded px-2 py-1 text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400">Cancel</button>
        </div>
      )}

      {/* Quick actions */}
      <div className="mb-4 flex flex-wrap items-center gap-1.5">
        {!voided && ro.status !== 'active' && (
          <button onClick={() => handleStatusChange('active')} className="rounded border border-blue-300 bg-blue-50 px-2.5 py-1 text-xs font-medium text-blue-700 hover:bg-blue-100 dark:border-blue-700 dark:bg-blue-900/20 dark:text-blue-400">Active</button>
        )}
        {!voided && !['in_progress', 'waiting_pickup', 'completed', 'final_close', 'delivered'].includes(ro.status) && (
          <button onClick={() => handleStatusChange('in_progress')} className="rounded border border-yellow-300 bg-yellow-50 px-2.5 py-1 text-xs font-medium text-yellow-700 hover:bg-yellow-100 dark:border-yellow-700 dark:bg-yellow-900/20 dark:text-yellow-400">In Progress</button>
        )}
        {!voided && !['waiting_parts', 'waiting_pickup', 'completed', 'final_close', 'delivered'].includes(ro.status) && (
          <button onClick={() => handleStatusChange('waiting_parts')} className="rounded border border-orange-300 bg-orange-50 px-2.5 py-1 text-xs font-medium text-orange-700 hover:bg-orange-100 dark:border-orange-700 dark:bg-orange-900/20 dark:text-orange-400">Waiting Parts</button>
        )}
        {!voided && !['waiting_pickup', 'completed', 'final_close', 'delivered'].includes(ro.status) && (
          <button onClick={() => handleStatusChange('waiting_pickup')} className="rounded border border-teal-300 bg-teal-50 px-2.5 py-1 text-xs font-medium text-teal-700 hover:bg-teal-100 dark:border-teal-700 dark:bg-teal-900/20 dark:text-teal-400">Waiting Pick-up</button>
        )}
        {!voided && !['completed', 'final_close', 'delivered'].includes(ro.status) && (
          <button onClick={() => handleStatusChange('completed')} className="rounded border border-green-300 bg-green-50 px-2.5 py-1 text-xs font-medium text-green-700 hover:bg-green-100 dark:border-green-700 dark:bg-green-900/20 dark:text-green-400">Complete</button>
        )}
        {!voided && ro.status === 'completed' && (
          <button onClick={() => handleStatusChange('final_close')} className="rounded border border-gray-300 bg-gray-50 px-2.5 py-1 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300">Final Close</button>
        )}
        {isCompletedStatus && !voided && (
          <button onClick={() => handleStatusChange('active')} className="rounded border border-gray-300 bg-gray-50 px-2.5 py-1 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300">Reopen</button>
        )}
        {ro.status === 'waiting_pickup' && !voided && (
          <>
            <button onClick={() => handleNotifyCustomer('sms')} className="inline-flex items-center gap-1 rounded border border-teal-300 bg-teal-50 px-2.5 py-1 text-xs font-medium text-teal-700 hover:bg-teal-100 dark:border-teal-700 dark:bg-teal-900/20 dark:text-teal-300"><Phone className="h-3 w-3" /> Notify SMS</button>
            <button onClick={() => handleNotifyCustomer('email')} className="inline-flex items-center gap-1 rounded border border-teal-300 bg-teal-50 px-2.5 py-1 text-xs font-medium text-teal-700 hover:bg-teal-100 dark:border-teal-700 dark:bg-teal-900/20 dark:text-teal-300"><Mail className="h-3 w-3" /> Notify Email</button>
          </>
        )}
        <span className="mx-1 h-4 w-px bg-gray-200 dark:bg-gray-700" />
        <button onClick={handleVoid} className={`inline-flex items-center gap-1 rounded border px-2.5 py-1 text-xs font-medium ${voided ? 'border-green-300 bg-green-50 text-green-700 hover:bg-green-100 dark:border-green-700 dark:bg-green-900/20 dark:text-green-300' : 'border-red-300 bg-red-50 text-red-700 hover:bg-red-100 dark:border-red-700 dark:bg-red-900/20 dark:text-red-300'}`}>
          <Ban className="h-3 w-3" /> {voided ? 'Un-void' : 'Void RO'}
        </button>
        <span className="mx-1 h-4 w-px bg-gray-200 dark:bg-gray-700" />
        <div className="flex items-center gap-1.5">
          <Clock3 className={`h-4 w-4 ${clockActive ? 'text-indigo-500' : 'text-gray-400'}`} />
          <span className="text-sm tabular-nums text-gray-700 dark:text-gray-200">{formatElapsed(clockElapsedMin)}</span>
          {clockActive ? (
            <button onClick={handleClockStop} className="rounded border border-indigo-300 bg-indigo-50 px-2 py-0.5 text-xs font-medium text-indigo-700 hover:bg-indigo-100 dark:border-indigo-700 dark:bg-indigo-900/20 dark:text-indigo-300">Stop</button>
          ) : (
            <button onClick={handleClockStart} className="rounded border border-gray-300 bg-white px-2 py-0.5 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300">Start</button>
          )}
        </div>
      </div>

      {/* Customer satisfaction */}
      {isCompletedStatus && !voided && (
        <div className="rounded-xl bg-white p-4 ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
          <p className="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">Customer Satisfaction</p>
          <div className="flex gap-0.5">
            {[1, 2, 3, 4, 5].map((star) => (
              <button key={star} onClick={() => handleSetSatisfaction(star)}
                className={`h-6 w-6 transition-colors ${(ro.satisfaction || 0) >= star ? 'text-yellow-400 hover:text-yellow-500' : 'text-gray-300 hover:text-yellow-300 dark:text-gray-600 dark:hover:text-yellow-500'}`}>
                <span className="text-xl leading-none">★</span>
              </button>
            ))}
            {!ro.satisfaction && <span className="ml-2 self-center text-xs text-gray-400">Not rated</span>}
          </div>
        </div>
      )}
    </div>
  );

  const servicesContent = (
    <div>
      {/* Sticky save bar */}
      <div className="sticky top-0 z-10 flex items-center justify-end gap-2 border-b border-gray-200 bg-gray-50 px-4 py-3 dark:border-gray-700 dark:bg-gray-950">
        {servicesSaved && <span className="text-xs text-green-600 dark:text-green-400">Saved</span>}
        <button onClick={handleSaveServices} disabled={saving || !servicesDirty}
          className="inline-flex items-center gap-1.5 rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 disabled:opacity-50">
          {saving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
          {saving ? 'Saving...' : 'Save Services'}
        </button>
      </div>

      {/* Catalog search */}
      <div className="mb-4 rounded-xl bg-white p-4 ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
        <h3 className="mb-3 text-sm font-semibold text-gray-700 dark:text-gray-300">Service Catalog</h3>
        <div className="relative">
          <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
          <input type="text" value={catalogSearch} onChange={(e) => setCatalogSearch(e.target.value)}
            placeholder="Search services from catalog..."
            className="w-full rounded-lg border border-gray-300 bg-white py-2 pl-9 pr-3 text-sm text-gray-900 placeholder-gray-400 focus:border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/20 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" />
        </div>
        {filteredCatalog.length > 0 && (
          <div className="mt-3 max-h-48 space-y-1.5 overflow-y-auto">
            {filteredCatalog.map((svc) => (
              <div key={svc.id} className="flex items-center gap-2 rounded-lg border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-700 dark:bg-gray-700/50">
                <div className="min-w-0">
                  <p className="text-sm font-medium text-gray-900 dark:text-gray-100">{svc.name}</p>
                  <p className="text-xs text-gray-500 dark:text-gray-400">{svc.category && `${svc.category} — `}${svc.price.toFixed(2)}</p>
                </div>
                <button onClick={() => handleAddCatalogService(svc)}
                  className="inline-flex shrink-0 items-center gap-1 rounded-lg bg-green-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-green-700">
                  <Plus className="h-3 w-3" /> Add
                </button>
              </div>
            ))}
          </div>
        )}
        {catalogSearch && filteredCatalog.length === 0 && (
          <p className="mt-2 text-xs text-gray-400">No matching services. <button onClick={() => setShowNewServiceForm(true)} className="text-blue-600 hover:underline dark:text-blue-400">Create one</button>.</p>
        )}
        {!showNewServiceForm && (
          <button onClick={() => setShowNewServiceForm(true)}
            className="mt-3 inline-flex items-center gap-1 text-xs font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400">
            <Plus className="h-3 w-3" /> Create new catalog service
          </button>
        )}
      </div>

      {/* New service form */}
      {showNewServiceForm && (
        <div className="mb-4 rounded-2xl border border-green-200 bg-green-50 p-5 shadow-sm dark:border-green-700 dark:bg-green-900/10">
          <div className="mb-4 flex items-center justify-between gap-3">
            <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100">Add New Service</h2>
            <button onClick={() => { setShowNewServiceForm(false); setNewServiceForm(createEmptyServiceForm()); }} className="text-gray-400 hover:text-gray-600"><X className="h-4 w-4" /></button>
          </div>
          <div className="grid gap-3 sm:grid-cols-2">
            <FormField label="Service Name"><Input value={newServiceForm.name} onChange={(v) => setNewServiceForm((p) => ({ ...p, name: v }))} placeholder="e.g. Oil Change" icon={<Wrench className="h-4 w-4" />} /></FormField>
            <FormField label="Category"><Input value={newServiceForm.category} onChange={(v) => setNewServiceForm((p) => ({ ...p, category: v }))} placeholder="e.g. Maintenance" icon={<Layers className="h-4 w-4" />} /></FormField>
          </div>
          <div className="mt-3">
            <FormField label="Description">
              <div className="space-y-2">
                <Textarea value={newServiceForm.description} onChange={(v) => setNewServiceForm((p) => ({ ...p, description: v }))} placeholder="Brief description..." rows={2} {...serviceTextSpellCheck} />
              </div>
            </FormField>
          </div>
          <div className="mt-3 rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-950/40">
            <p className="text-sm font-medium text-gray-700 dark:text-gray-300">Pricing</p>
            <div className="mt-3 grid gap-2 sm:grid-cols-2">
              <button type="button" onClick={() => setNewServiceForm((p) => ({ ...p, pricingMode: 'full' }))}
                className={`rounded-lg border px-4 py-3 text-left text-sm transition-colors ${newServiceForm.pricingMode === 'full' ? 'border-green-500 bg-green-50 text-green-700 dark:border-green-500 dark:bg-green-900/20 dark:text-green-300' : 'border-gray-300 bg-white text-gray-700 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:hover:bg-gray-800'}`}>
                <span className="block font-medium">Full Price</span>
                <span className="block text-xs text-gray-500 dark:text-gray-400">Single flat price</span>
              </button>
              <button type="button" onClick={() => setNewServiceForm((p) => ({ ...p, pricingMode: 'split' }))}
                className={`rounded-lg border px-4 py-3 text-left text-sm transition-colors ${newServiceForm.pricingMode === 'split' ? 'border-green-500 bg-green-50 text-green-700 dark:border-green-500 dark:bg-green-900/20 dark:text-green-300' : 'border-gray-300 bg-white text-gray-700 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:hover:bg-gray-800'}`}>
                <span className="block font-medium">Labor + Parts</span>
                <span className="block text-xs text-gray-500 dark:text-gray-400">Split pricing</span>
              </button>
            </div>
            {newServiceForm.pricingMode === 'full' ? (
              <div className="mt-3">
                <FormField label="Full Price ($)"><Input type="number" value={newServiceForm.fullPrice} onChange={(v) => setNewServiceForm((p) => ({ ...p, fullPrice: Number(v) || 0 }))} icon={<Tag className="h-4 w-4" />} /></FormField>
              </div>
            ) : (
              <div className="mt-3 grid gap-3 sm:grid-cols-3">
                <FormField label="Labor Price ($)"><Input type="number" value={newServiceForm.laborPrice} onChange={(v) => setNewServiceForm((p) => ({ ...p, laborPrice: Number(v) || 0 }))} icon={<DollarSign className="h-4 w-4" />} /></FormField>
                <FormField label="Parts Price ($)"><Input type="number" value={newServiceForm.partsPrice} onChange={(v) => setNewServiceForm((p) => ({ ...p, partsPrice: Number(v) || 0 }))} icon={<Package className="h-4 w-4" />} /></FormField>
                <FormField label="Total">
                  <div className="flex h-10 items-center rounded-lg border border-gray-300 bg-gray-50 px-3 text-sm font-medium text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100">
                    <Tag className="mr-2 h-4 w-4 text-gray-400" />${(newServiceForm.laborPrice + newServiceForm.partsPrice).toFixed(2)}
                  </div>
                </FormField>
              </div>
            )}
          </div>
          <div className="mt-4 flex justify-end gap-2">
            <button onClick={() => { setShowNewServiceForm(false); setNewServiceForm(createEmptyServiceForm()); }}
              className="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800">
              <X className="h-4 w-4" /> Cancel
            </button>
            <button onClick={handleSaveNewService}
              className="inline-flex items-center gap-1.5 rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700">
              <Check className="h-4 w-4" /> Create & Add
            </button>
          </div>
        </div>
      )}

      {/* Current RO services */}
      <div className="mb-4 rounded-xl bg-white p-4 ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
        <div className="mb-3 flex items-center justify-between">
          <h3 className="text-sm font-semibold text-gray-700 dark:text-gray-300">RO Services</h3>
          <button onClick={handleAddService}
            className="inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700">
            <Plus className="h-3.5 w-3.5" /> Add Manual
          </button>
        </div>
        <div className="space-y-3">
          {localServices.map((svc, i) => (
            <EditableServiceRow key={i} service={svc} index={i} onChange={handleServiceChange} onRemove={handleRemoveService} defaultLaborRate={settings.defaultLaborRate || 145} {...serviceTextSpellCheck} />
          ))}
          {localServices.length === 0 && (
            <p className="text-center text-sm text-gray-400">No services on this RO yet.</p>
          )}
        </div>
      </div>

      {/* Totals + Save */}
      {localServices.filter((s) => s.name?.trim()).length > 0 && (
        <div className="mb-4 rounded-xl bg-white p-4 ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
          <div className="mx-auto max-w-md overflow-hidden rounded-xl border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-900/40">
            <div className="border-b border-gray-200 px-4 py-3 dark:border-gray-700">
              <h3 className="text-sm font-semibold text-gray-800 dark:text-gray-100">RO Total</h3>
              <p className="mt-0.5 text-xs text-gray-500 dark:text-gray-400">Services and required charges only</p>
            </div>
            <div className="space-y-2 px-4 py-3 text-sm">
              <div className="flex justify-between"><span className="text-gray-500 dark:text-gray-400">Labor</span><span className="font-medium text-gray-900 dark:text-gray-100">{formatCurrency(totals.laborTotal)}</span></div>
              <div className="flex justify-between"><span className="text-gray-500 dark:text-gray-400">Parts</span><span className="font-medium text-gray-900 dark:text-gray-100">{formatCurrency(totals.partsTotal)}</span></div>
              <div className="flex justify-between border-t border-gray-200 pt-2 dark:border-gray-700"><span className="font-medium text-gray-700 dark:text-gray-300">Services Subtotal</span><span className="font-semibold text-gray-900 dark:text-gray-100">{formatCurrency(totals.subtotal)}</span></div>
              {(totals.discountAmount > 0 || totals.shopCharge > 0 || totals.tax > 0) && (
                <div className="space-y-2 border-t border-gray-200 pt-2 dark:border-gray-700">
                  {totals.discountAmount > 0 && <div className="flex justify-between"><span className="text-gray-500 dark:text-gray-400">Discount</span><span className="font-medium text-green-600 dark:text-green-400">−{formatCurrency(totals.discountAmount)}</span></div>}
                  {totals.shopCharge > 0 && <div className="flex justify-between"><span className="text-gray-500 dark:text-gray-400">Shop Charge</span><span className="font-medium text-gray-900 dark:text-gray-100">{formatCurrency(totals.shopCharge)}</span></div>}
                  {totals.tax > 0 && <div className="flex justify-between"><span className="text-gray-500 dark:text-gray-400">{settings.taxLabel || 'Tax'}</span><span className="font-medium text-gray-900 dark:text-gray-100">{formatCurrency(totals.tax)}</span></div>}
                </div>
              )}
            </div>
            <div className="flex items-center justify-between bg-blue-50 px-4 py-3 dark:bg-blue-950/30">
              <span className="text-sm font-bold text-gray-900 dark:text-white">Total Due</span>
              <span className="text-xl font-bold text-blue-600 dark:text-blue-400">{formatCurrency(totals.total)}</span>
            </div>
          </div>
        </div>
      )}
    </div>
  );

  const financialContent = (
    <div>
      {/* Sticky save bar */}
      <div className="sticky top-0 z-10 flex items-center justify-end gap-2 border-b border-gray-200 bg-gray-50 px-4 py-3 dark:border-gray-700 dark:bg-gray-950">
        {finSaved && <span className="text-xs text-green-600 dark:text-green-400">Saved</span>}
        <button onClick={handleSaveFinancial} disabled={finSaving}
          className="inline-flex items-center gap-1.5 rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 disabled:opacity-50">
          {finSaving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
          {finSaving ? 'Saving...' : 'Save Financial'}
        </button>
      </div>

      <div className="space-y-4 p-4">
        {/* Helper text */}
        <div className="rounded-lg border border-blue-200 bg-blue-50 p-3 text-xs text-blue-700 dark:border-blue-700 dark:bg-blue-900/20 dark:text-blue-300">
          <DollarSign className="mr-1 inline h-3.5 w-3.5" />
          Enter the actual billed amounts and costs. Warranty totals and costs are deducted from Customer Pay. Shop charge is deducted from Customer Pay gross profits.
        </div>

        {/* Customer Pay section */}
        <div className="rounded-xl border border-green-200 bg-green-50 p-4 dark:border-green-700 dark:bg-green-900/10">
          <h3 className="mb-3 text-sm font-bold text-green-800 dark:text-green-300">Customer Pay</h3>
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
            <div>
              <label className="block text-xs font-semibold text-gray-500 uppercase">CP Total</label>
              <input type="number" step="0.01" value={finCpTotal} onChange={(e) => setFinCpTotal(e.target.value)} placeholder="0.00"
                className="mt-1 w-full rounded-lg border border-gray-300 bg-white p-2 text-sm focus:ring-2 focus:ring-green-500 focus:outline-none dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" />
            </div>
            <div>
              <label className="block text-xs font-semibold text-gray-500 uppercase">CP Cost</label>
              <input type="number" step="0.01" value={finCpCost} onChange={(e) => setFinCpCost(e.target.value)} placeholder="0.00"
                className="mt-1 w-full rounded-lg border border-gray-300 bg-white p-2 text-sm focus:ring-2 focus:ring-green-500 focus:outline-none dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" />
            </div>
            <div>
              <label className="block text-xs font-semibold text-gray-500 uppercase">CP Net Total</label>
              <div className="mt-1 flex h-[38px] items-center rounded-lg border border-green-200 bg-green-100 px-2 text-sm font-medium text-green-800 dark:border-green-700 dark:bg-green-900/30 dark:text-green-300">
                {formatCurrency(cpNetTotal)}
              </div>
              <p className="mt-1 text-[10px] text-gray-400">CP Total minus Warranty Total</p>
            </div>
          </div>
          <div className="mt-2 grid grid-cols-1 gap-3 sm:grid-cols-2">
            <div className="rounded-lg bg-white p-2 dark:bg-gray-800">
              <div className="flex justify-between text-xs">
                <span className="text-gray-500 dark:text-gray-400">CP Net Cost</span>
                <span className="font-medium text-gray-900 dark:text-gray-100">{formatCurrency(cpNetCost)}</span>
              </div>
              <p className="mt-0.5 text-[10px] text-gray-400">CP Cost minus Warranty Cost</p>
            </div>
            <div className="rounded-lg bg-white p-2 dark:bg-gray-800">
              <div className="flex justify-between text-xs">
                <span className="text-gray-500 dark:text-gray-400">CP Gross Profit</span>
                <span className={`font-bold ${cpGrossProfit >= 0 ? 'text-green-700 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>{formatCurrency(cpGrossProfit)}</span>
              </div>
              <p className="mt-0.5 text-[10px] text-gray-400">Net Total minus Net Cost minus Shop Charge</p>
            </div>
          </div>
        </div>

        {/* Warranty section */}
        <div className="rounded-xl border border-blue-200 bg-blue-50 p-4 dark:border-blue-700 dark:bg-blue-900/10">
          <h3 className="mb-3 text-sm font-bold text-blue-800 dark:text-blue-300">Warranty</h3>
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
            <div>
              <label className="block text-xs font-semibold text-gray-500 uppercase">Warranty Total</label>
              <input type="number" step="0.01" value={finWarrTotal} onChange={(e) => setFinWarrTotal(e.target.value)} placeholder="0.00"
                className="mt-1 w-full rounded-lg border border-gray-300 bg-white p-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" />
            </div>
            <div>
              <label className="block text-xs font-semibold text-gray-500 uppercase">Warranty Cost</label>
              <input type="number" step="0.01" value={finWarrCost} onChange={(e) => setFinWarrCost(e.target.value)} placeholder="0.00"
                className="mt-1 w-full rounded-lg border border-gray-300 bg-white p-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" />
            </div>
            <div>
              <label className="block text-xs font-semibold text-gray-500 uppercase">Warranty GP</label>
              <div className="mt-1 flex h-[38px] items-center rounded-lg border border-blue-200 bg-blue-100 px-2 text-sm font-medium text-blue-800 dark:border-blue-700 dark:bg-blue-900/30 dark:text-blue-300">
                {formatCurrency(warrGrossProfit)}
              </div>
              <p className="mt-1 text-[10px] text-gray-400">Warranty Total minus Warranty Cost</p>
            </div>
          </div>
        </div>

        {/* Shop Charge section */}
        <div className="rounded-xl border border-amber-200 bg-amber-50 p-4 dark:border-amber-700 dark:bg-amber-900/10">
          <h3 className="mb-3 text-sm font-bold text-amber-800 dark:text-amber-300">Shop Charge</h3>
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
            <div>
              <label className="block text-xs font-semibold text-gray-500 uppercase">Shop Charge</label>
              <input type="number" step="0.01" value={finShopCharge} onChange={(e) => setFinShopCharge(e.target.value)} placeholder="0.00"
                className="mt-1 w-full rounded-lg border border-gray-300 bg-white p-2 text-sm focus:ring-2 focus:ring-amber-500 focus:outline-none dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" />
              <p className="mt-1 text-[10px] text-gray-400">Deducted from CP Gross Profit</p>
            </div>
            <div className="flex items-end">
              <div className="w-full rounded-lg bg-white p-2 dark:bg-gray-800">
                <div className="flex justify-between text-xs">
                  <span className="text-gray-500 dark:text-gray-400">CP GP after Shop Charge</span>
                  <span className={`font-bold ${cpGrossProfit >= 0 ? 'text-green-700 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>{formatCurrency(cpGrossProfit)}</span>
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* Gross Profit summary */}
        <div className="rounded-xl bg-gray-100 p-4 dark:bg-gray-700/50">
          <div className="flex items-center justify-between">
            <div className="text-sm font-medium text-gray-600 dark:text-gray-300">Overall Gross Profit</div>
            <div className={`text-2xl font-bold ${overallGrossProfit >= 0 ? 'text-gray-900 dark:text-white' : 'text-red-600 dark:text-red-400'}`}>{formatCurrency(overallGrossProfit)}</div>
          </div>
          <div className="mt-2 flex gap-4 text-xs text-gray-500 dark:text-gray-400">
            <span>CP GP: <strong className={cpGrossProfit >= 0 ? 'text-green-700 dark:text-green-400' : 'text-red-600 dark:text-red-400'}>{formatCurrency(cpGrossProfit)}</strong></span>
            <span>Warranty GP: <strong className={warrGrossProfit >= 0 ? 'text-blue-700 dark:text-blue-400' : 'text-red-600 dark:text-red-400'}>{formatCurrency(warrGrossProfit)}</strong></span>
          </div>
        </div>
      </div>
    </div>
  );

  const historyContent = (
    <div>
      {!ro.vin || !ro.vin.trim() ? (
        <div className="rounded-xl bg-white p-8 text-center ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
          <History className="mx-auto h-10 w-10 text-gray-300 dark:text-gray-600" />
          <p className="mt-3 text-sm text-gray-500 dark:text-gray-400">No VIN on this repair order — vehicle history unavailable.</p>
        </div>
      ) : historyLoading ? (
        <div className="flex items-center justify-center py-12"><LoadingSpinner text="Loading history..." /></div>
      ) : historyData.length === 0 ? (
        <div className="rounded-xl bg-white p-8 text-center ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
          <History className="mx-auto h-10 w-10 text-gray-300 dark:text-gray-600" />
          <p className="mt-3 text-sm text-gray-500 dark:text-gray-400">No previous records found for VIN {ro.vin}.</p>
        </div>
      ) : (
        <div className="space-y-3">
          {historyData.map((item) => (
            <div key={`${item.type}-${item.id}`} className="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-900">
              <div className="flex items-start justify-between gap-3">
                <div className="min-w-0 flex-1">
                  <div className="flex flex-wrap items-center gap-2">
                    <span className={`rounded-full px-2 py-0.5 text-xs font-medium ${item.type === 'ro' ? 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300' : 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300'}`}>{item.type === 'ro' ? 'RO' : 'Quote'}</span>
                    <span className="text-sm font-semibold text-gray-900 dark:text-gray-100">{item.title}</span>
                    <StatusBadge status={item.status} config={statusConfig} />
                  </div>
                  {item.vehicleInfo && <p className="mt-1 text-xs text-gray-500 dark:text-gray-400">{item.vehicleInfo}</p>}
                  <p className="mt-1 text-xs text-gray-400">{formatDateTime(item.date)}</p>
                </div>
                <div className="text-right">
                  <p className="text-sm font-semibold text-green-600 dark:text-green-400">{formatCurrency(item.total)}</p>
                </div>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );

  function formatFieldName(field: string): string {
    return field
      .replace(/([A-Z])/g, ' $1')
      .replace(/^./, (s) => s.toUpperCase())
      .trim();
  }

  const timelineContent = (
    <div className="rounded-xl bg-white p-4 ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-gray-700">
      <h3 className="mb-2 text-sm font-semibold text-gray-700 dark:text-gray-300">Audit Timeline</h3>
      {events.length === 0 ? (
        <p className="text-sm text-gray-400">No recorded events.</p>
      ) : (
        <ol className="divide-y divide-gray-100 dark:divide-gray-700">
          {events.map((ev) => <TimelineEntry key={ev.id} ev={ev} />)}
        </ol>
      )}

      {financialAuditLoading ? (
        <div className="mt-6 flex items-center justify-center py-4">
          <Loader2 className="h-4 w-4 animate-spin text-gray-400" />
        </div>
      ) : financialAuditEntries.length > 0 && (
        <div className="mt-6">
          <h3 className="mb-3 text-sm font-semibold text-gray-700 dark:text-gray-300">Financial Audit Trail</h3>
          <div className="space-y-2">
            {financialAuditEntries.map((entry) => (
              <div
                key={entry.id}
                className="rounded-lg border border-gray-200 bg-gray-50 p-3 text-sm dark:border-gray-700 dark:bg-gray-800/50"
              >
                <div className="flex flex-wrap items-center gap-1.5">
                  <span className="rounded bg-blue-100 px-1.5 py-0.5 text-xs font-medium text-blue-700 dark:bg-blue-900/30 dark:text-blue-300">
                    {formatFieldName(entry.field)}
                  </span>
                  <span className="text-xs text-gray-400">
                    {formatDateTime(entry.at)}
                  </span>
                </div>
                <div className="mt-1.5 flex flex-col gap-1">
                  <div className="flex flex-wrap items-baseline gap-2">
                    <span className="font-mono text-[11px] text-gray-500 bg-gray-100 rounded px-1.5 py-0.5 dark:bg-gray-700 dark:text-gray-400">
                      {JSON.stringify(entry.from)}
                    </span>
                    <span className="text-gray-400">→</span>
                    <span className="font-mono text-[11px] text-gray-700 bg-gray-100 rounded px-1.5 py-0.5 dark:bg-gray-700 dark:text-gray-300">
                      {JSON.stringify(entry.to)}
                    </span>
                  </div>
                  <div className="flex flex-wrap items-center gap-3 text-xs text-gray-400">
                    {entry.by && <span>by {entry.by}</span>}
                    <span
                      className="font-mono text-[10px] text-gray-400 cursor-help"
                      title={entry.hash}
                    >
                      #{entry.hash?.slice(0, 8)}...
                    </span>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );

  const activeTabContent = (() => {
    switch (activeTab) {
      case 'details': return detailsContent;
      case 'services': return servicesContent;
      case 'financial': return financialContent;
      case 'history': return historyContent;
      case 'timeline': return timelineContent;
    }
  })();

  const content = (
    <div className="flex h-full flex-col">
      {/* Tab bar */}
      <div className="flex items-center gap-1 border-b border-gray-200 bg-gray-50 p-2 dark:border-gray-700 dark:bg-gray-900">
        <button onClick={closeModal}
          className="mr-2 rounded-lg p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-600 dark:hover:bg-gray-800 dark:hover:text-gray-300">
          <X className="h-4 w-4" />
        </button>
        <div className="flex gap-1">
          {TABS.map((tab) => (
            <button key={tab.id} onClick={() => setActiveTab(tab.id)}
              className={`inline-flex items-center gap-1.5 rounded-lg px-3 py-2 text-sm font-medium transition-colors ${
                activeTab === tab.id
                  ? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400'
                  : 'text-gray-500 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200'
              }`}>
              <tab.icon className="h-4 w-4" />
              {tab.label}
            </button>
          ))}
        </div>
        {/* Status badge for reference */}
        <div className="ml-auto flex items-center gap-2">
          <span className="text-xs text-gray-400">{ro.roNumber || `#${ro.id.slice(0, 8)}`}</span>
          <StatusBadge status={voided ? 'voided' : (ro.status || '')} config={statusConfig} />
        </div>
      </div>

      {/* Tab content */}
      <div className="flex-1 overflow-y-auto p-4">
        {activeTabContent}
      </div>
    </div>
  );

  if (!isModal) {
    return (
      <div className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
        <div className="mb-8">
          <h1 className="text-2xl font-bold text-gray-900 dark:text-white">Repair Order Details</h1>
          <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
            <button onClick={closeModal} className="inline-flex items-center gap-1 text-blue-600 hover:underline"><ArrowLeft className="h-4 w-4" /> Back to Repair Orders</button>
          </p>
        </div>
        {content}
      </div>
    );
  }

  return (
    <div className="fixed inset-0 z-50">
      <button type="button" aria-label="Close" className="absolute inset-0 bg-gray-950/45 backdrop-blur-sm" onClick={closeModal} />
      <div className="absolute inset-0 flex items-center justify-center p-3 sm:p-6">
        <div className="relative flex h-[min(92vh,56rem)] w-full max-w-7xl overflow-hidden rounded-3xl border border-gray-200 bg-gray-50 shadow-2xl dark:border-gray-700 dark:bg-gray-950">
          <div className="flex-1 overflow-hidden">
            {content}
          </div>
        </div>
      </div>

      <AddTimeModal
        open={showAddTimeModal}
        initialMinutes={15}
        onCancel={() => setShowAddTimeModal(false)}
        onConfirm={(totalMinutes) => { setShowAddTimeModal(false); if (totalMinutes > 0) handleAddTime(totalMinutes); }}
      />
    </div>
  );
}
