// ==================================================================================
// OTO HUB - Main App (OOP: components/views/modals loaded from separate files)
// ==================================================================================

const { useState, useEffect, useRef } = React;

// Use components and utilities from loaded modules (window.*)
const ErrorBoundary = window.ErrorBoundary;
const TagsInput = window.TagsInput;
const validateKBForm = window.validateKBForm;
const VersionHistoryPanel = window.VersionHistoryPanel;
const AttachmentManager = window.AttachmentManager;
const ContactPrefIcons = window.ContactPrefIcons;
const PropertySelector = window.PropertySelector;
const MarkdownText = window.MarkdownText;
const HistoryVersionsButton = window.HistoryVersionsButton;
const RoleModal = window.RoleModal;
const ArticleModal = window.ArticleModal;
const PropertiesManagementModal = window.PropertiesManagementModal;
const AIChatView = window.AIChatView;
const ITSupportView = window.ITSupportView;
const AccessManagementView = window.AccessManagementView;
const ContactInformationView = window.ContactInformationView;
const VendorsView = window.VendorsView;
const VenuesView = window.VenuesView;
const AdministrationView = window.AdministrationView;
const formatDate = window.formatDate;
const getRelativeTime = window.getRelativeTime;
const formatPreferredContactMethods = window.formatPreferredContactMethods;
const getStatusColor = window.getStatusColor;
const sortPropertiesOTOThenAZ = window.sortPropertiesOTOThenAZ;
const normalizeKbMetadata = window.normalizeKbMetadata;
const getKbAudience = window.getKbAudience;
const getKbAttachments = window.getKbAttachments;

window.KBComponents = { TagsInput, validateKBForm, VersionHistoryPanel, AttachmentManager };

        // Sidebar theme: one place to change blend, hover, and shadow. Exposed for PropertySelector (sidebar variant).
        const OTOSidebarTheme = {
            // Sidebar container – blends with gradient; no white tint
            sidebarRoot: 'flex flex-col w-64 flex-shrink-0 border-r border-black/10 overflow-hidden',
            sidebarHeader: 'px-5 pt-6 pb-4 border-b border-black/10',
            sidebarNavLabel: 'text-blue-200/60 text-[11px] font-semibold mb-2.5 px-2 uppercase tracking-widest',
            sidebarNavItem: 'w-full text-left px-3 py-2.5 rounded-xl text-sm font-medium transition-all text-blue-100/95 hover:bg-black/15 hover:text-white',
            sidebarNavItemActive: 'w-full text-left px-3 py-2.5 rounded-xl text-sm font-medium transition-all bg-black/20 text-white shadow-md',
            sidebarLogoutFooter: 'p-3 border-t border-black/10 bg-black/5',
            sidebarLogoutButton: 'w-full text-left px-3 py-2.5 rounded-xl text-sm font-medium text-blue-100/90 hover:bg-black/15 hover:text-white transition-all flex items-center gap-2.5',
            // Property card when used in sidebar (darker hover, medium shadow, blends)
            propertyCard: 'bg-black/10 border border-black/20 rounded-xl p-4',
            propertyLabel: 'text-white/70 text-[10px] font-semibold uppercase tracking-wider',
            propertyBorder: 'border-black/20',
            propertySelect: 'w-full bg-black/15 border border-black/25 text-white rounded-lg px-3 py-2.5 pr-8 text-sm font-semibold focus:outline-none focus:ring-2 focus:ring-black/20 cursor-pointer appearance-none transition-all hover:border-black/40',
            propertyButtonHover: 'hover:bg-black/15',
            propertyDashedBorder: 'border-2 border-dashed border-black/20 rounded-lg',
        };
        if (typeof window !== 'undefined') window.OTOSidebarTheme = OTOSidebarTheme;

        // Main App Component
        const App = () => {
            const [isAuthenticated, setIsAuthenticated] = useState(false);
            const [activeView, setActiveView] = useState('chat');
            const [showCreateTicket, setShowCreateTicket] = useState(false);
            const [ticketDescription, setTicketDescription] = useState('');
            const [ticketDraft, setTicketDraft] = useState(null); // Store full AI draft
            const [createTicketOrigin, setCreateTicketOrigin] = useState('it');
            const [showPropertiesModal, setShowPropertiesModal] = useState(false);
            const [currentUser, setCurrentUser] = useState({
                FirstName: "Hotel",
                LastName: "Rep",
                Username: "hotelrep",
                Email: "user@company.com",
                Phone: "(555) 123-4567",
                Role: "Front Desk",
                properties: []
            });
            const [selectedProperty, setSelectedProperty] = useState(null);
            const [pendingKbDraft, setPendingKbDraft] = useState(null); // KB article draft from AI for user to submit
            
            const canManageProperties = window.canManageProperties ? window.canManageProperties(currentUser) : !!currentUser.can_manage_properties;
            const canAccessPropertyManagement = window.canAccessPropertyManagement ? window.canAccessPropertyManagement(currentUser) : (!!currentUser?.can_manage_properties || !!currentUser?.can_manage_venues);
            // Admin nav: show if user has Manage Settings, any KB permission, or View Audit Logs.
            const isAdmin = window.canAccessAdmin ? window.canAccessAdmin(currentUser) : (
                (currentUser?.can_manage_settings === true)
                || (currentUser?.can_manage_knowledge_base === true)
                || (currentUser?.can_approve_knowledge_base === true)
                || (currentUser?.can_view_knowledge_base === true)
                || (currentUser?.can_submit_knowledge_base === true)
                || (currentUser?.can_edit_knowledge_base === true)
                || (currentUser?.can_view_audit_logs === true)
            );
            const adminNavLabel = window.getAdminNavLabel ? window.getAdminNavLabel(currentUser) : (
                (currentUser?.can_manage_settings === true) ? 'Administration' : (
                    (currentUser?.can_view_audit_logs === true && (currentUser?.can_manage_knowledge_base === true || currentUser?.can_view_knowledge_base === true)) ? 'Knowledge Base & Audit' :
                    (currentUser?.can_manage_knowledge_base === true || currentUser?.can_view_knowledge_base === true) ? 'Knowledge Base' :
                    (currentUser?.can_view_audit_logs === true) ? 'Audit' : 'Administration'
                )
            );
            const canAccessAI = window.canAccessAI ? window.canAccessAI(currentUser) : !!(
                currentUser?.can_access_general_ai || currentUser?.can_access_it_support || currentUser?.can_access_capex_support
            );
            
            // Listen for login events from other tabs to prevent duplicate portal tabs
            useEffect(() => {
                const handleStorageChange = (e) => {
                    // If another tab just logged in, close this tab if we're on the login page
                    if (e.key === 'oto_portal_login' && e.newValue && !isAuthenticated) {
                        try {
                            const loginData = JSON.parse(e.newValue);
                            // Check if this was a recent login (within last 2 seconds)
                            if (Date.now() - loginData.timestamp < 2000) {
                                // Another tab just logged in - close this one
                                window.close();
                            }
                        } catch (err) {
                            // Ignore parse errors
                        }
                    }
                };
                
                window.addEventListener('storage', handleStorageChange);
                return () => window.removeEventListener('storage', handleStorageChange);
            }, [isAuthenticated]);
            
            // Set selected property when user properties are available
            // Prefer OTO if available, otherwise use first property
            useEffect(() => {
                if (currentUser.properties && currentUser.properties.length > 0 && !selectedProperty) {
                    // Sort properties: OTO first, then alphabetically
                    const sortedProps = [...currentUser.properties].sort((a, b) => {
                        if (a.property_code === 'OTO') return -1;
                        if (b.property_code === 'OTO') return 1;
                        return a.property_code.localeCompare(b.property_code);
                    });
                    setSelectedProperty(sortedProps[0]); // Now this will be OTO if user has it
                }
            }, [currentUser.properties]);
            
            // AI Chat state is stored at the App level so it persists when switching views
            // Default greeting is marked as system/display-only so it's not sent to backend; text is permission-based (see getAIAssistantGreeting).
            const [chatMessages, setChatMessages] = useState([
                {
                    role: 'assistant',
                    content:
                        (window.getAIAssistantGreeting && window.getAIAssistantGreeting(null)) ||
                        "Hi! I'm your OTO Assistant. I can help with property information, directory lookups, knowledge base articles, and general questions about OTO-HUB.\n\nHow can I help you today?",
                    isSystemMessage: true,
                }
            ]);
            const [chatAttachments, setChatAttachments] = useState([]);
            const [chatAllAttachments, setChatAllAttachments] = useState([]);

            const [ticketAttachments, setTicketAttachments] = useState([]);

            const handleCreateTicketFromChat = (draft, attachments = []) => {
                // draft contains: {subject, description, priority, category}
                setTicketDraft(draft); // Store the full draft
                setTicketDescription(draft.description || '');
                setTicketAttachments(attachments);
                setCreateTicketOrigin('chat');  // Remember we came from AI Assistant
                setActiveView('it');
                setShowCreateTicket(true);
            };

            const handleBackToChat = (isSubmitted = false) => {
                setActiveView('chat');
                setShowCreateTicket(false);
                setTicketDescription('');
                setTicketAttachments([]);
                setCreateTicketOrigin('it');
                
                    if (isSubmitted) {
                    // Clear chat for new conversation after successful submission
                    setChatMessages([
                        {
                            role: 'assistant',
                            content:
                                (window.getAIAssistantGreeting && window.getAIAssistantGreeting(currentUser)) ||
                                "Hi! I'm your OTO Assistant. I can help with property information, directory lookups, knowledge base articles, and general questions about OTO-HUB.\n\nHow can I help you today?",
                            isSystemMessage: true,
                        }
                    ]);
                    setChatAttachments([]);
                    setChatAllAttachments([]);
                    setTicketDraft(null);
                }
                // If cancelled (isSubmitted = false), keep context - don't clear anything
            };

            const handleShowCreateForm = (show, description = '') => {
                if (show) {
                    setCreateTicketOrigin('it');  // Opened from IT Support
                }
                setShowCreateTicket(show);
                setTicketDescription(description);
            };

	            const handleLoginSuccess = async (user) => {
	                const username = user?.username || 'hotelrep';
	                let phoneNumber = '';
	                let preferredMethods = ['email'];
                try {
                    const response = await fetch(`/api/contact/${username}`, {
                        headers: window.getApiHeaders ? window.getApiHeaders(username) : { 'X-OTO-User': username }
                    });
                    if (response.ok) {
                        const data = await response.json();
                        preferredMethods = Array.isArray(data.preferred_contact_methods) && data.preferred_contact_methods.length
                            ? data.preferred_contact_methods
                            : ['email'];
                        if (data.phone) {
                            const cleaned = data.phone.replace(/\D/g, '');
                            if (cleaned.length === 10) {
                                phoneNumber = `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6, 10)}`;
                            } else {
                                phoneNumber = data.phone;
                            }
                        }
                    }
                } catch (err) {
                    console.error('Failed to fetch contact info at login:', err);
                }

                const permissions = (window.applyPermissionsFromUser && window.applyPermissionsFromUser(user))
                    || (user && Object.fromEntries(Object.keys(user).filter(k => k.startsWith('can_')).map(k => [k, !!user[k]])))
                    || {};
                setCurrentUser(prev => ({
                    ...prev,
                    Email: user?.email || '',
                    FirstName: user?.first_name || 'Hotel',
                    LastName: user?.last_name || 'Rep',
                    Username: username,
                    Role: user?.role_display_name || user?.role_name || 'Front Desk',
                    Phone: phoneNumber,
                    PreferredContactMethods: preferredMethods,
                    properties: user?.properties || [],
                    ...permissions,
                }));

                setActiveView('chat');
                setIsAuthenticated(true);
                try { localStorage.setItem('oto_username', username); } catch (e) { /* ignore */ }
                
                // Clear chat on new login
                setChatMessages([
                    {
                        role: 'assistant',
                        content:
                            (window.getAIAssistantGreeting && window.getAIAssistantGreeting(user)) ||
                            "Hi! I'm your OTO Assistant. I can help with property information, directory lookups, knowledge base articles, and general questions about OTO-HUB.\n\nHow can I help you today?",
                        isSystemMessage: true,
                    }
                ]);
                setChatAttachments([]);
                setChatAllAttachments([]);
            };

            // Refresh current user from API (role, permissions, properties). Used when role/staff updated elsewhere.
            const refreshCurrentUser = React.useCallback(async () => {
                const username = currentUser?.Username || (typeof localStorage !== 'undefined' && localStorage.getItem('oto_username'));
                if (!username) return;
                try {
                    const meRes = await fetch('/api/auth/me', {
                        headers: window.getApiHeaders ? window.getApiHeaders(username) : { 'X-OTO-User': username }
                    });
                    if (!meRes.ok) return;
                    const meData = await meRes.json();
                    const user = meData.user;
                    if (!user) return;
                    let phoneNumber = (currentUser && currentUser.Phone) || '';
                    let preferredMethods = (currentUser && currentUser.PreferredContactMethods) || ['email'];
                    try {
                        const contactRes = await fetch(`/api/contact/${username}`, {
                            headers: window.getApiHeaders ? window.getApiHeaders(username) : { 'X-OTO-User': username }
                        });
                        if (contactRes.ok) {
                            const contact = await contactRes.json();
                            preferredMethods = Array.isArray(contact.preferred_contact_methods) && contact.preferred_contact_methods.length
                                ? contact.preferred_contact_methods : ['email'];
                            if (contact.phone) {
                                const cleaned = String(contact.phone).replace(/\D/g, '');
                                phoneNumber = cleaned.length === 10
                                    ? `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6, 10)}` : contact.phone;
                            }
                        }
                    } catch (_) { /* keep existing phone/prefs */ }
                    const permissions = (window.applyPermissionsFromUser && window.applyPermissionsFromUser(user))
                        || (user && Object.fromEntries(Object.keys(user).filter(k => k.startsWith('can_')).map(k => [k, !!user[k]])))
                        || {};
                    setCurrentUser(prev => ({
                        ...prev,
                        Email: user.email || prev.Email,
                        FirstName: user.first_name || prev.FirstName,
                        LastName: user.last_name || prev.LastName,
                        Username: user.username || username,
                        Role: user.role_display_name || user.role_name || prev.Role,
                        Phone: phoneNumber,
                        PreferredContactMethods: preferredMethods,
                        properties: user.properties || prev.properties || [],
                        ...permissions,
                    }));
                } catch (e) {
                    console.error('Refresh current user failed', e);
                }
            }, [currentUser?.Username, currentUser?.Phone, currentUser?.PreferredContactMethods]);

            // Live updates: when role/staff/permissions change elsewhere, refresh app state
            useEffect(() => {
                if (!window.otoEvents || !isAuthenticated) return;
                const unsub = window.otoEvents.on('current-user-updated', refreshCurrentUser);
                return () => { if (typeof unsub === 'function') unsub(); };
            }, [isAuthenticated, refreshCurrentUser]);

            // When user returns to this tab (visibility), refresh current user so permission changes from another tab appear.
            const wasHiddenRef = React.useRef(false);
            useEffect(() => {
                if (!isAuthenticated) return;
                const onVisibilityChange = () => {
                    if (document.visibilityState === 'hidden') wasHiddenRef.current = true;
                    if (document.visibilityState === 'visible' && wasHiddenRef.current) {
                        wasHiddenRef.current = false;
                        refreshCurrentUser();
                    }
                };
                document.addEventListener('visibilitychange', onVisibilityChange);
                return () => document.removeEventListener('visibilitychange', onVisibilityChange);
            }, [isAuthenticated, refreshCurrentUser]);

            // Periodic refresh of permissions so role changes (e.g. by an admin) are reflected without leaving the tab
            // Short interval so client UIs react quickly when their role/permissions change.
            const PERMISSION_REFRESH_INTERVAL_MS = 15 * 1000;
            useEffect(() => {
                if (!isAuthenticated) return;
                const interval = setInterval(refreshCurrentUser, PERMISSION_REFRESH_INTERVAL_MS);
                return () => clearInterval(interval);
            }, [isAuthenticated, refreshCurrentUser]);

            // When permissions change (e.g. after refresh or role update), force user out of any view they no longer have access to
            useEffect(() => {
                if (!isAuthenticated || !currentUser?.Username) return;
                if (typeof window.isViewAllowed !== 'function' || typeof window.getFirstAllowedView !== 'function') return;
                if (!window.isViewAllowed(activeView, currentUser)) {
                    const first = window.getFirstAllowedView(currentUser);
                    setActiveView(first);
                    setShowPropertiesModal(false);
                    if (window.otoNotify?.toast) {
                        window.otoNotify.toast('Your permissions have changed. You were moved to a different section.', 'info', { duration: 4000 });
                    }
                }
            }, [isAuthenticated, currentUser, activeView]);

            const OTONotifyPortal = window.OTONotifyPortal;

            if (!isAuthenticated) {
                return (
                    <>
                        <LoginPage onLoginSuccess={handleLoginSuccess} />
                        {OTONotifyPortal && <OTONotifyPortal />}
                    </>
                );
            }

            return (
                <>
                <div className="flex h-screen overflow-hidden bg-gradient-to-br from-primary-dark via-primary to-primary-hover">
                    <div className={OTOSidebarTheme.sidebarRoot}>
                        <div className={OTOSidebarTheme.sidebarHeader}>
                            <h1 className="text-white text-2xl font-bold tracking-tight mb-1">OTO HUB</h1>
                            <p className="text-blue-200/90 text-xs font-medium uppercase tracking-wider mb-3">Signed in as</p>
                            <div className="text-white font-semibold text-sm mb-4">
                                {currentUser.FirstName} {currentUser.LastName}
                            </div>
                            {typeof PropertySelector === 'function' ? (
                                <PropertySelector 
                                    userProperties={currentUser.properties}
                                    selectedProperty={selectedProperty}
                                    onPropertyChange={setSelectedProperty}
                                    onSettingsClick={() => setShowPropertiesModal(true)}
                                    canManageProperties={canAccessPropertyManagement}
                                    variant="sidebar"
                                />
                            ) : (
                                <div className="text-white/80 text-sm">Loading...</div>
                            )}
                        </div>
                        
                        <div className="flex-1 py-4 px-3">
                            <p className={OTOSidebarTheme.sidebarNavLabel}>Navigation</p>
                            <nav className="space-y-1">
                                {canAccessAI && (
                                <button
                                    onClick={() => { setActiveView('chat'); setShowCreateTicket(false); }}
                                    className={activeView === 'chat' ? OTOSidebarTheme.sidebarNavItemActive : OTOSidebarTheme.sidebarNavItem}
                                >
                                    AI Assistant
                                </button>
                                )}
                                {window.canViewDirectory && window.canViewDirectory(currentUser) && (
                                <button
                                    onClick={() => { setActiveView('access'); setShowCreateTicket(false); }}
                                    className={activeView === 'access' ? OTOSidebarTheme.sidebarNavItemActive : OTOSidebarTheme.sidebarNavItem}
                                >
                                    Directory
                                </button>
                                )}
                                <button
                                    onClick={() => { setActiveView('contact'); setShowCreateTicket(false); }}
                                    className={activeView === 'contact' ? OTOSidebarTheme.sidebarNavItemActive : OTOSidebarTheme.sidebarNavItem}
                                >
                                    My Profile
                                </button>
                                {isAdmin ? (
                                    <button
                                        onClick={() => { setActiveView('admin'); setShowCreateTicket(false); }}
                                        className={activeView === 'admin' ? OTOSidebarTheme.sidebarNavItemActive : OTOSidebarTheme.sidebarNavItem}
                                    >
                                        {adminNavLabel}
                                    </button>
                                ) : null}
                            </nav>
                        </div>
                        
                        <div className={OTOSidebarTheme.sidebarLogoutFooter}>
                            <button
                                onClick={() => {
                                    setIsAuthenticated(false);
                                    // Clear chat on logout
                                    setChatMessages([
                                        { role: 'assistant', content: (window.getAIAssistantGreeting && window.getAIAssistantGreeting(currentUser)) || "Hi! I'm your IT Assistant. I can help troubleshoot issues and, when needed, help you create a support ticket.\n\nHow can I help you today?", isSystemMessage: true }
                                    ]);
                                    setChatAttachments([]);
                                    setChatAllAttachments([]);
                                }}
                                className={OTOSidebarTheme.sidebarLogoutButton}
                            >
                                <svg className="w-5 h-5 flex-shrink-0 opacity-90" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
                                </svg>
                                Logout
                            </button>
                        </div>
                    </div>

                    <div className="flex-1 overflow-hidden bg-white rounded-l-2xl shadow-2xl flex flex-col min-w-0">
                        {activeView === 'chat' && !canAccessAI && (
                            <div className="flex items-center justify-center h-full text-slate-500 p-8">
                                <p className="text-center">You do not have access to the AI Assistant. Contact your administrator for General Information AI or IT Support permissions.</p>
                            </div>
                        )}
                        {activeView === 'chat' && canAccessAI && (
                            typeof AIChatView === 'function' ? (
                            <AIChatView
                                onCreateTicket={handleCreateTicketFromChat}
                                onClearChat={() => setTicketDraft(null)}
                                messages={chatMessages}
                                setMessages={setChatMessages}
                                attachments={chatAttachments}
                                setAttachments={setChatAttachments}
                                allAttachments={chatAllAttachments}
                                setAllAttachments={setChatAllAttachments}
                                selectedProperty={selectedProperty}
                                currentUser={currentUser}
                                onOpenKbDraft={(draft) => { setPendingKbDraft(draft); setActiveView('admin'); }}
                            />
                            ) : (
                                <div className="flex items-center justify-center h-full text-slate-500 p-8">Loading AI Assistant...</div>
                            )
                        )}
                        {activeView === 'it' && typeof ITSupportView === 'function' && <ITSupportView 
                            showCreateForm={showCreateTicket} 
                            onShowCreateForm={handleShowCreateForm} 
                            initialDescription={ticketDescription}
                            initialDraft={ticketDraft}
                            initialAttachments={ticketAttachments}
                            fromAIChat={createTicketOrigin === 'chat'}
                            onBackToChat={handleBackToChat}
                        />}
                        {activeView === 'access' && typeof AccessManagementView === 'function' && <AccessManagementView currentUser={currentUser} selectedProperty={selectedProperty} isActiveView={activeView === 'access'} />}
                        {activeView === 'contact' && typeof ContactInformationView === 'function' && <ContactInformationView currentUser={currentUser} setCurrentUser={setCurrentUser} />}
                        {activeView === 'admin' && typeof AdministrationView === 'function' && <AdministrationView currentUser={currentUser} userProperties={currentUser.properties || []} isActiveView={activeView === 'admin'} pendingKbDraft={pendingKbDraft} onClearPendingKbDraft={() => setPendingKbDraft(null)} />}
                    </div>
                    
                    {/* Properties Management Modal */}
                    {typeof PropertiesManagementModal === 'function' && (
                        <PropertiesManagementModal 
                            isOpen={showPropertiesModal} 
                            onClose={() => setShowPropertiesModal(false)}
                            onDataChange={() => {}}
                            currentUser={currentUser} 
                            selectedPropertyContext={selectedProperty}
                            onPropertyChange={(property) => setSelectedProperty(property)}
                        />
                    )}
                    {typeof OTONotifyPortal === 'function' && <OTONotifyPortal />}
                </div>
                </>
            );
        };

        // Login Page Component
        const LoginPage = ({ onLoginSuccess }) => {
            const [step, setStep] = useState('email'); // 'email' or 'code'
            const [email, setEmail] = useState('');
            const [code, setCode] = useState('');
            const [isLoading, setIsLoading] = useState(false);
            const [error, setError] = useState('');
            const [successMessage, setSuccessMessage] = useState('');
            const [resendCooldown, setResendCooldown] = useState(0); // Seconds remaining until can resend
            const [lastResendTime, setLastResendTime] = useState(null);

            // Countdown timer for resend cooldown
            useEffect(() => {
                if (resendCooldown > 0) {
                    const timer = setTimeout(() => {
                        setResendCooldown(resendCooldown - 1);
                    }, 1000);
                    return () => clearTimeout(timer);
                }
            }, [resendCooldown]);

            // Auto-dismiss messages after 7 seconds
            useEffect(() => {
                if (error) {
                    const timer = setTimeout(() => setError(''), 7000);
                    return () => clearTimeout(timer);
                }
            }, [error]);

            useEffect(() => {
                if (successMessage) {
                    const timer = setTimeout(() => setSuccessMessage(''), 7000);
                    return () => clearTimeout(timer);
                }
            }, [successMessage]);

            // Check if user came from magic link (URL parameters)
            useEffect(() => {
                const params = new URLSearchParams(window.location.search);
                const userParam = params.get('user');
                const errorParam = params.get('error');

                if (errorParam && !userParam) {
                    const map = {
                        account_disabled: 'Your account is disabled. Please contact IT support.',
                        account_locked: 'Your account is locked. Please contact IT support.',
                        invalid_token: 'That login link is invalid. Please request a new code.',
                        token_used: 'That login link has already been used. Please request a new code.',
                        token_expired: 'That login link has expired. Please request a new code.',
                        invalid_or_expired: 'That login link is invalid or has expired. Please request a new code.',
                        user_not_found: 'User not found. Please request a new code.',
                        server_error: 'An error occurred. Please try again or request a new code.'
                    };
                    setError(map[errorParam] || 'Unable to sign in. Please request a new code.');
                }

                if (userParam) {
                    (async () => {
                        try {
                            const userData = JSON.parse(userParam);
                            
                            // Try to communicate with existing portal tabs
                            // Set a flag in localStorage that we're logging in
                            try {
                                localStorage.setItem('oto_portal_login', JSON.stringify({
                                    timestamp: Date.now(),
                                    userData: userData
                                }));
                            } catch (e) {
                                console.log('LocalStorage not available');
                            }
                            
                            // User clicked magic link - log them in
                            await onLoginSuccess(
                                userData.email, 
                                userData.first_name, 
                                userData.last_name, 
                                userData.username,
                                userData.properties || [],
                                userData.role || ''
                            );
                            
                            // Clear URL parameters after successful login for clean URL
                            window.history.replaceState({}, document.title, "/");
                            
                            // Clear the login flag after a short delay
                            setTimeout(() => {
                                try {
                                    localStorage.removeItem('oto_portal_login');
                                } catch (e) {
                                    // Ignore
                                }
                            }, 1000);
                        } catch (e) {
                            console.error('Failed to parse user data from URL', e);
                            setError('Failed to process login. Please request a new code.');
                        }
                    })();
                }
            }, []);

            const handleEmailSubmit = async (e) => {
                e.preventDefault();
                setError('');
                setSuccessMessage('');
                
                if (!email) {
                    setError('Please enter your email address');
                    return;
                }
                
                // Basic email validation
                const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
                if (!emailRegex.test(email)) {
                    setError('Please enter a valid email address');
                    return;
                }

                setIsLoading(true);
                setError('');

                const showCodeStep = () => {
                    setIsLoading(false);
                    setStep('code');
                    setResendCooldown(300);
                    setLastResendTime(Date.now());
                };

                // Call backend API (15s timeout so SMTP slowness doesn't hang the UI)
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 15000);
                try {
                    const response = await fetch('/api/auth/request-code', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ email: email.toLowerCase().trim() }),
                        signal: controller.signal,
                    });
                    clearTimeout(timeoutId);

                    let data;
                    try {
                        data = await response.json();
                    } catch (_) {
                        // Server returned non-JSON (e.g. error page); still show code step so user can enter code from logs
                        showCodeStep();
                        setSuccessMessage('Request sent. If you didn’t get the email, enter the code from server logs below.');
                        return;
                    }

                    if (!response.ok) {
                        throw new Error(data.detail || 'Failed to send verification');
                    }

                    showCodeStep();
                    setSuccessMessage('📧 Sending verification email...');
                    setTimeout(() => setSuccessMessage(`✉️ Verification code sent to ${email}`), 2000);
                } catch (err) {
                    clearTimeout(timeoutId);
                    if (err.name === 'AbortError') {
                        // Timeout - request may have succeeded; show code step so user can enter code from logs
                        showCodeStep();
                        setSuccessMessage('Request may have succeeded. Enter the code from your email or server logs below.');
                    } else {
                        setIsLoading(false);
                        setError(err.message || 'Failed to send verification. Please try again.');
                    }
                }
            };

            const handleCodeSubmit = async (e) => {
                e.preventDefault();
                setError('');
                setSuccessMessage('');
                
                if (!code) {
                    setError('Please enter the verification code');
                    return;
                }

                if (code.length !== 6) {
                    setError('Verification code must be 6 digits');
                    return;
                }

                setIsLoading(true);
                
                // Call backend API for code verification
                try {
                    const response = await fetch('/api/auth/verify-code', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify({ 
                            email: email.toLowerCase().trim(),
                            code: code.trim()
                        })
                    });

                    const data = await response.json();

                    if (!response.ok) {
                        throw new Error(data.detail || 'Invalid verification code');
                    }

                    setIsLoading(false);
                    setSuccessMessage('Login successful!');
                    
                    // Wait a moment then log in
                    setTimeout(async () => {
                        await onLoginSuccess(data.user);
                    }, 800);

                } catch (err) {
                    setIsLoading(false);
                    setError(err.message || 'Invalid verification code. Please try again.');
                }
            };

            const handleResendCode = async () => {
                // Check if still in cooldown
                if (resendCooldown > 0) {
                    setError(`Please wait ${Math.floor(resendCooldown / 60)}:${(resendCooldown % 60).toString().padStart(2, '0')} before requesting another code`);
                    return;
                }
                
                setError('');
                setSuccessMessage('');
                setIsLoading(true);

                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 15000);
                try {
                    const response = await fetch('/api/auth/request-code', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ email: email.toLowerCase().trim() }),
                        signal: controller.signal,
                    });
                    clearTimeout(timeoutId);
                    const data = await response.json().catch(() => ({}));
                    if (!response.ok) {
                        throw new Error(data.detail || 'Failed to resend code');
                    }
                    setIsLoading(false);
                    setSuccessMessage('📧 Sending new verification code...');
                    setTimeout(() => setSuccessMessage('✉️ New verification code has been sent to your email'), 2000);
                    setResendCooldown(300);
                    setLastResendTime(Date.now());
                } catch (err) {
                    clearTimeout(timeoutId);
                    setIsLoading(false);
                    setError(err.name === 'AbortError' ? 'Request timed out. You can still enter the code from server logs.' : (err.message || 'Failed to resend code. Please try again.'));
                }
            };

            const handleBackToEmail = () => {
                setStep('email');
                setCode('');
                setError('');
                setSuccessMessage('');
            };

            return (
                <div className="min-h-screen bg-gradient-to-br from-primary-dark via-primary to-primary-hover flex items-center justify-center p-4">
                    <div className="w-full max-w-md">
                        {/* Header */}
                        <div className="text-center mb-12">
                            <h1 className="text-4xl font-bold text-white tracking-tight">OTO HUB</h1>
                        </div>

                        {/* Login Card */}
                        <div className="bg-white rounded-2xl shadow-xl overflow-hidden border border-white/20">
                            {step === 'email' ? (
                                <>
                                    <div className="px-10 pt-10 pb-8">
                                        <h2 className="text-3xl font-bold text-slate-800 mb-8">Sign In</h2>

                                        <form onSubmit={handleEmailSubmit}>
                                            <div className="mb-6">
                                                <input
                                                    type="email"
                                                    value={email}
                                                    onChange={(e) => setEmail(e.target.value)}
                                                    placeholder="Enter your work email"
                                                    className="w-full border-2 border-slate-200 rounded-xl px-5 py-4 text-slate-800 placeholder-slate-400 focus:outline-none focus:border-primary focus:ring-4 focus:ring-primary/10 transition-all text-base"
                                                    disabled={isLoading}
                                                    autoFocus
                                                />
                                            </div>

                                            {error && (
                                                <div className="mb-6 bg-red-50 border-l-4 border-red-500 text-red-700 px-5 py-4 rounded-r-lg text-sm">
                                                    {error}
                                                </div>
                                            )}

                                            {successMessage && (
                                                <div className="mb-6 bg-primary/10 border-l-4 border-primary text-primary px-5 py-4 rounded-r-lg text-sm">
                                                    {successMessage}
                                                </div>
                                            )}

                                            <button
                                                type="submit"
                                                disabled={isLoading}
                                                className="w-full bg-primary hover:bg-primary-hover text-white font-semibold py-4 rounded-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed shadow-lg hover:shadow-xl text-base"
                                            >
                                                {isLoading ? (
                                                    <span className="flex items-center justify-center gap-3">
                                                        <svg className="animate-spin h-5 w-5" fill="none" viewBox="0 0 24 24">
                                                            <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
                                                            <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                                                        </svg>
                                                        Sending code...
                                                    </span>
                                                ) : (
                                                    'Continue'
                                                )}
                                            </button>
                                        </form>
                                    </div>


                                </>
                            ) : (
                                <>
                                    <div className="px-10 pt-10 pb-8">
                                        <button
                                            onClick={handleBackToEmail}
                                            className="text-primary hover:text-primary-hover font-semibold flex items-center gap-2 mb-8 transition-colors text-sm"
                                        >
                                            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
                                            </svg>
                                            Back
                                        </button>
                                        
                                        <h2 className="text-3xl font-bold text-slate-800 mb-3">Enter Code</h2>
                                        <p className="text-slate-600 text-sm mb-2">
                                            Sent to <span className="font-semibold text-slate-800">{email}</span>
                                        </p>
                                        <p className="text-slate-500 text-xs mb-8">
                                            If you didn’t receive the email, the code may appear in server logs (e.g. Render logs).
                                        </p>

                                        <form onSubmit={handleCodeSubmit}>
                                            <div className="mb-6">
                                                <input
                                                    type="text"
                                                    value={code}
                                                    onChange={(e) => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
                                                    placeholder="000000"
                                                    className="w-full border-2 border-slate-200 rounded-xl px-5 py-5 text-center text-3xl font-mono tracking-[0.5em] text-slate-800 focus:outline-none focus:border-primary focus:ring-4 focus:ring-primary/10 transition-all"
                                                    disabled={isLoading}
                                                    maxLength="6"
                                                    autoComplete="off"
                                                    autoFocus
                                                />
                                            </div>

                                            {error && (
                                                <div className="mb-6 bg-red-50 border-l-4 border-red-500 text-red-700 px-5 py-4 rounded-r-lg text-sm">
                                                    {error}
                                                </div>
                                            )}

                                            {successMessage && (
                                                <div className="mb-6 bg-primary/10 border-l-4 border-primary text-primary px-5 py-4 rounded-r-lg text-sm">
                                                    {successMessage}
                                                </div>
                                            )}

                                            <button
                                                type="submit"
                                                disabled={isLoading}
                                                className="w-full bg-primary hover:bg-primary-hover text-white font-semibold py-4 rounded-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed shadow-lg hover:shadow-xl text-base mb-4"
                                            >
                                                {isLoading ? (
                                                    <span className="flex items-center justify-center gap-3">
                                                        <svg className="animate-spin h-5 w-5" fill="none" viewBox="0 0 24 24">
                                                            <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
                                                            <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                                                        </svg>
                                                        Verifying...
                                                    </span>
                                                ) : (
                                                    'Verify & Sign In'
                                                )}
                                            </button>

                                            <button
                                                type="button"
                                                onClick={handleResendCode}
                                                disabled={isLoading || resendCooldown > 0}
                                                className="w-full text-primary hover:text-primary-hover font-semibold py-3 text-sm disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                                            >
                                                {resendCooldown > 0 ? (
                                                    `Resend available in ${Math.floor(resendCooldown / 60)}:${(resendCooldown % 60).toString().padStart(2, '0')}`
                                                ) : (
                                                    "Didn't receive a code? Resend"
                                                )}
                                            </button>
                                        </form>
                                    </div>


                                </>
                            )}
                        </div>

                        {/* Footer */}
                        <div className="mt-10 text-center text-blue-100 text-sm space-y-2">
                            <p className="font-semibold">OTO Development - OTO HUB</p>
                            <p className="text-xs leading-relaxed opacity-90">
                                Can't login? Alternatively, you can contact<br />
                                OTO IT Support at <a href="mailto:ITSupport@otodevelopment.com" className="hover:text-white transition-colors underline font-medium">ITSupport@otodevelopment.com</a>
                            </p>
                        </div>
                    </div>
                </div>
            );
        };

        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(
            <ErrorBoundary>
                <App />
            </ErrorBoundary>
        );
