import { useEffect, useState, useCallback, useRef } from 'react';
import { useOutletContext, useLocation } from 'react-router-dom';
import {
  Typography,
  Tabs,
  Form,
  Input,
  InputNumber,
  Switch,
  Button,
  ColorPicker,
  Alert,
  Divider,
  Space,
  Segmented,
  Tag,
  Descriptions,
  Card,
  Collapse,
  Row,
  Col,
  Slider,
  Progress,
  Steps,
  Modal,
  Checkbox,
  Timeline,
  Select,
  message,
  Spin,
} from 'antd';
import {
  SettingOutlined,
  SaveOutlined,
  ThunderboltOutlined,
  SendOutlined,
  CheckCircleOutlined,
  CloseCircleOutlined,
  InfoCircleOutlined,
  AppstoreOutlined,
  PlaySquareOutlined,
  MessageOutlined,
  TeamOutlined,
  DollarOutlined,
  AlertOutlined,
  MailOutlined,
  RetweetOutlined,
  PhoneOutlined,
  CloudSyncOutlined,
  SyncOutlined,
  BranchesOutlined,
  HistoryOutlined,
  RocketOutlined,
  ExclamationCircleOutlined,
  LoadingOutlined,
  ReloadOutlined,
  ClockCircleOutlined,
  BarChartOutlined,
} from '@ant-design/icons';
import { useSettingsStore } from '@/stores/settings.store';
import { api } from '@/lib/api';
import { useMobile } from '@/hooks/useMobile';
import { PageTour } from '@/components/tour/PageTour';
import type { AppOutletContext } from '@/components/AppLayout';
import type { SmtpTestResult, SmtpSendTestResult, UpgradeStatusResponse, UpgradeStatus, UpgradeProgress, UpgradeResult, UpgradeHistoryResponse, WatcherHealth } from '@/types/api';

const { Text, Paragraph } = Typography;

export default function SettingsPage() {
  const { setPageHeader } = useOutletContext<AppOutletContext>();
  const { isMobile } = useMobile();
  const locationState = useLocation().state as { activeTab?: string } | null;
  const { settings, loading, fetchAdminSettings, updateSettings } = useSettingsStore();
  const [form] = Form.useForm();

  const [testingConnection, setTestingConnection] = useState(false);
  const [connectionResult, setConnectionResult] = useState<SmtpTestResult | null>(null);
  const [sendingTest, setSendingTest] = useState(false);
  const [sendResult, setSendResult] = useState<SmtpSendTestResult | null>(null);

  useEffect(() => {
    setPageHeader({ title: 'Settings' });
    return () => setPageHeader(null);
  }, [setPageHeader]);

  useEffect(() => {
    fetchAdminSettings();
  }, [fetchAdminSettings]);

  useEffect(() => {
    if (settings) {
      form.setFieldsValue(settings);
    }
  }, [settings, form]);

  const handleSave = async () => {
    try {
      const values = form.getFieldsValue();

      // Convert ColorPicker values to hex strings
      const colorFields = [
        'adminColorPrimary',
        'adminColorBgBase',
        'publicColorPrimary',
        'publicColorBgBase',
        'publicColorBgContainer',
      ] as const;

      for (const field of colorFields) {
        const val = values[field];
        if (val && typeof val === 'object' && 'toHexString' in val) {
          values[field] = val.toHexString();
        }
      }

      await updateSettings(values);
      setConnectionResult(null);
      setSendResult(null);
      message.success('Settings saved successfully');
    } catch {
      message.error('Failed to save settings');
    }
  };

  const handleTestConnection = async () => {
    setTestingConnection(true);
    setConnectionResult(null);
    try {
      const { data } = await api.post<SmtpTestResult>('/settings/email/test-connection');
      setConnectionResult(data);
    } catch {
      setConnectionResult({ success: false, message: 'Request failed' });
    } finally {
      setTestingConnection(false);
    }
  };

  const handleSendTest = async () => {
    setSendingTest(true);
    setSendResult(null);
    try {
      const to = form.getFieldValue('testEmailRecipient');
      const { data } = await api.post<SmtpSendTestResult>('/settings/email/test-send', { to });
      setSendResult(data);
    } catch {
      setSendResult({ success: false, testMode: false, recipient: '' });
    } finally {
      setSendingTest(false);
    }
  };

  const handleProviderToggle = async (value: string | number) => {
    const provider = value as 'mailhog' | 'production';
    try {
      await updateSettings({ smtpActiveProvider: provider });
      form.setFieldsValue({ smtpActiveProvider: provider });
      message.success(`Switched to ${provider === 'mailhog' ? 'MailHog' : 'Production'} SMTP`);
      setConnectionResult(null);
      setSendResult(null);
    } catch {
      message.error('Failed to switch SMTP provider');
    }
  };

  if (loading) {
    return (
      <div style={{ textAlign: 'center', padding: 80 }}>
        <Spin size="large" />
      </div>
    );
  }

  const items = [
    {
      key: 'organization',
      label: 'Organization',
      icon: <SettingOutlined />,
      children: (
        <div style={{ maxWidth: isMobile ? undefined : 600 }} data-tour-settings-org>
          <Form.Item label="Organization Name" name="organizationName">
            <Input placeholder="Changemaker Lite" />
          </Form.Item>
          <Form.Item label="Short Name" name="organizationShortName" extra="Shown when sidebar is collapsed (max 10 chars)">
            <Input placeholder="CML" maxLength={10} />
          </Form.Item>
          <Form.Item label="Logo URL" name="organizationLogoUrl">
            <Input placeholder="https://example.com/logo.png" />
          </Form.Item>
          <Form.Item label="Favicon URL" name="organizationFaviconUrl">
            <Input placeholder="https://example.com/favicon.ico" />
          </Form.Item>
          <Form.Item label="Footer Text" name="footerText">
            <Input placeholder="Powered by Changemaker Lite" />
          </Form.Item>
          <Form.Item label="Login Subtitle" name="loginSubtitle" extra="Shown below the organization name on the login page">
            <Input placeholder="Admin" />
          </Form.Item>
        </div>
      ),
    },
    {
      key: 'theme',
      label: 'Theme Colors',
      children: (
        <div style={{ maxWidth: isMobile ? undefined : 600 }} data-tour-settings-theme>
          <Text strong style={{ fontSize: 15 }}>Admin Theme</Text>
          <Divider style={{ margin: '12px 0' }} />
          <Form.Item label="Primary Color" name="adminColorPrimary">
            <ColorPicker format="hex" showText />
          </Form.Item>
          <Form.Item label="Background Color" name="adminColorBgBase">
            <ColorPicker format="hex" showText />
          </Form.Item>

          <div style={{ marginTop: 24 }}>
            <Text strong style={{ fontSize: 15 }}>Public Theme</Text>
            <Divider style={{ margin: '12px 0' }} />
            <Form.Item label="Primary Color" name="publicColorPrimary">
              <ColorPicker format="hex" showText />
            </Form.Item>
            <Form.Item label="Background Color" name="publicColorBgBase">
              <ColorPicker format="hex" showText />
            </Form.Item>
            <Form.Item label="Container Color" name="publicColorBgContainer">
              <ColorPicker format="hex" showText />
            </Form.Item>
            <Form.Item label="Header Gradient" name="publicHeaderGradient">
              <GradientPicker />
            </Form.Item>
          </div>

          {settings && (
            <div style={{ marginTop: 24 }}>
              <Text strong style={{ fontSize: 15 }}>Preview</Text>
              <Divider style={{ margin: '12px 0' }} />
              <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
                <Swatch label="Admin Primary" color={settings.adminColorPrimary} />
                <Swatch label="Admin BG" color={settings.adminColorBgBase} />
                <Swatch label="Public Primary" color={settings.publicColorPrimary} />
                <Swatch label="Public BG" color={settings.publicColorBgBase} />
                <Swatch label="Public Container" color={settings.publicColorBgContainer} />
              </div>
            </div>
          )}
        </div>
      ),
    },
    {
      key: 'email',
      label: 'Email',
      children: (() => {
        const eff = settings?._effective;
        const isMailhog = (settings?.smtpActiveProvider || 'mailhog') === 'mailhog';

        return (
          <div style={{ maxWidth: isMobile ? undefined : 600 }} data-tour-settings-email>
            {/* Current Configuration Summary */}
            {eff && (
              <Card size="small" style={{ marginBottom: 24 }}>
                <Descriptions
                  title={
                    <Space>
                      <InfoCircleOutlined />
                      <span>Current Email Configuration</span>
                    </Space>
                  }
                  column={1}
                  size="small"
                >
                  <Descriptions.Item label="Provider">
                    <Tag color={eff.provider === 'mailhog' ? 'orange' : 'green'}>
                      {eff.provider === 'mailhog' ? 'MailHog' : 'Production'}
                    </Tag>
                  </Descriptions.Item>
                  <Descriptions.Item label="Server">
                    <Text code>{eff.host}:{eff.port}</Text>
                  </Descriptions.Item>
                  <Descriptions.Item label="From">
                    <Text>{`"${eff.fromName}" <${eff.fromAddress}>`}</Text>
                  </Descriptions.Item>
                  <Descriptions.Item label="Authentication">
                    {eff.user ? (
                      <Text><CheckCircleOutlined style={{ color: '#52c41a', marginRight: 4 }} />{eff.user}</Text>
                    ) : (
                      <Text type="secondary">None</Text>
                    )}
                  </Descriptions.Item>
                  <Descriptions.Item label="Test Mode">
                    {eff.testMode ? (
                      <Text><Tag color="orange">ON</Tag> redirecting to {eff.testRecipient}</Text>
                    ) : (
                      <Tag color="green">OFF</Tag>
                    )}
                  </Descriptions.Item>
                </Descriptions>
              </Card>
            )}

            {/* Sender */}
            <Text strong style={{ fontSize: 15 }}>Sender</Text>
            <Divider style={{ margin: '12px 0' }} />
            <Form.Item label="From Name" name="emailFromName" extra="The sender name used in outgoing emails">
              <Input placeholder="Changemaker Lite" />
            </Form.Item>
            <Form.Item label="From Address" name="smtpFromAddress" extra="The sender email address">
              <Input placeholder="noreply@cmlite.org" />
            </Form.Item>

            {/* Active SMTP Provider */}
            <div style={{ marginTop: 24 }}>
              <Text strong style={{ fontSize: 15 }}>Active SMTP Provider</Text>
              <Divider style={{ margin: '12px 0' }} />
              <div style={{ marginBottom: 16 }}>
                <Segmented
                  value={settings?.smtpActiveProvider || 'mailhog'}
                  options={[
                    { label: 'MailHog', value: 'mailhog' },
                    { label: 'Production', value: 'production' },
                  ]}
                  onChange={handleProviderToggle}
                  size="large"
                />
                <Tag
                  color="green"
                  style={{ marginLeft: 12, verticalAlign: 'middle' }}
                >
                  {isMailhog ? 'MailHog Active' : 'Production Active'}
                </Tag>
              </div>
            </div>

            {/* MailHog Info */}
            {isMailhog && (
              <div style={{ marginTop: 24 }}>
                <Text strong style={{ fontSize: 15 }}>MailHog (Testing)</Text>
                <Divider style={{ margin: '12px 0' }} />
                <div style={{ padding: '12px 16px', background: 'rgba(255,255,255,0.04)', borderRadius: 8, border: '1px solid rgba(255,255,255,0.08)' }}>
                  <div><Text type="secondary">Host:</Text> <Text code>mailhog-changemaker</Text></div>
                  <div style={{ marginTop: 4 }}><Text type="secondary">Port:</Text> <Text code>1025</Text></div>
                  <div style={{ marginTop: 4 }}><Text type="secondary">Auth:</Text> <Text type="secondary">None required</Text></div>
                  <div style={{ marginTop: 4 }}><Text type="secondary">Web UI:</Text> <Text code>http://localhost:8025</Text></div>
                </div>
              </div>
            )}

            {/* Production SMTP */}
            <div style={{ marginTop: 24, opacity: isMailhog ? 0.45 : 1, pointerEvents: isMailhog ? 'none' : 'auto' }}>
              <Collapse
                defaultActiveKey={!isMailhog ? ['smtp'] : []}
                items={[{
                  key: 'smtp',
                  label: (
                    <Space>
                      <Text strong>Production SMTP Credentials</Text>
                      {isMailhog && <Tag>Not active</Tag>}
                    </Space>
                  ),
                  children: (
                    <div>
                      <Form.Item label="SMTP Host" name="smtpHost" extra="Production mail server hostname">
                        <Input placeholder="smtp.protonmail.ch" />
                      </Form.Item>
                      <Form.Item label="SMTP Port" name="smtpPort" extra="Common ports: 587 (STARTTLS), 465 (SSL)">
                        <InputNumber min={0} max={65535} style={{ width: '100%' }} placeholder="587" />
                      </Form.Item>
                      <Form.Item label="SMTP User" name="smtpUser">
                        <Input placeholder="user@example.com" />
                      </Form.Item>
                      <Form.Item label="SMTP Password" name="smtpPass">
                        <Input.Password placeholder="SMTP password or app-specific password" />
                      </Form.Item>
                    </div>
                  ),
                }]}
              />
            </div>

            {/* Test Mode */}
            <div style={{ marginTop: 24 }}>
              <Text strong style={{ fontSize: 15 }}>Test Mode</Text>
              <Divider style={{ margin: '12px 0' }} />
              <Form.Item
                label="Enable Test Mode"
                name="emailTestMode"
                valuePropName="checked"
                extra="When enabled, all emails are redirected to the test recipient"
              >
                <Switch />
              </Form.Item>
              <Form.Item label="Test Recipient" name="testEmailRecipient" extra="All emails will be sent to this address when test mode is on">
                <Input placeholder="admin@cmlite.org" />
              </Form.Item>
            </div>

            {/* Test Actions */}
            <div style={{ marginTop: 24 }}>
              <Text strong style={{ fontSize: 15 }}>Test Actions</Text>
              <Divider style={{ margin: '12px 0' }} />
              <Alert
                type="info"
                message={eff
                  ? `Testing against ${eff.provider === 'mailhog' ? 'MailHog' : 'Production'} (${eff.host}:${eff.port})`
                  : 'Tests run against the active provider. Save production credentials before switching.'
                }
                showIcon
                style={{ marginBottom: 16 }}
              />
              <Space>
                <Button
                  icon={<ThunderboltOutlined />}
                  loading={testingConnection}
                  onClick={handleTestConnection}
                >
                  Test Connection
                </Button>
                <Button
                  icon={<SendOutlined />}
                  loading={sendingTest}
                  onClick={handleSendTest}
                >
                  Send Test Email
                </Button>
              </Space>

              {connectionResult && (
                <Alert
                  type={connectionResult.success ? 'success' : 'error'}
                  message={connectionResult.message}
                  icon={connectionResult.success ? <CheckCircleOutlined /> : <CloseCircleOutlined />}
                  showIcon
                  style={{ marginTop: 12 }}
                />
              )}

              {sendResult && (
                <Alert
                  type={sendResult.success ? 'success' : 'error'}
                  message={
                    sendResult.success
                      ? `Test email sent to ${sendResult.recipient}${sendResult.testMode ? ' (test mode)' : ''}`
                      : 'Failed to send test email'
                  }
                  description={sendResult.messageId ? `Message ID: ${sendResult.messageId}` : undefined}
                  showIcon
                  style={{ marginTop: 12 }}
                />
              )}
            </div>
          </div>
        );
      })(),
    },
    {
      key: 'features',
      label: 'Feature Toggles',
      children: (
        <div data-tour-settings-features>
          <Alert
            type="info"
            message="Disabling a module hides it from navigation but does not delete data."
            showIcon
            style={{ marginBottom: 24 }}
          />
          <Row gutter={[16, 16]}>
            {/* Core Platform */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><AppstoreOutlined /> Core Platform</Space>}
              >
                <Form.Item label="Advocacy Campaigns" name="enableInfluence" valuePropName="checked" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Petitions" name="enablePetitions" valuePropName="checked" extra="Public petition pages with signature collection, progress tracking, and campaign linking" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Straw Polls" name="enablePolls" valuePropName="checked" extra="Quick opinion polls with public landers and MkDocs widgets" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Map & Canvassing" name="enableMap" valuePropName="checked" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Newsletter (Listmonk)" name="enableNewsletter" valuePropName="checked" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Landing Pages" name="enableLandingPages" valuePropName="checked" style={{ marginBottom: 0 }}>
                  <Switch />
                </Form.Item>
              </Card>
            </Col>

            {/* Media & Content */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><PlaySquareOutlined /> Media & Content</Space>}
              >
                <Form.Item label="Media Library" name="enableMediaFeatures" valuePropName="checked" extra="Video library, public gallery, analytics, and scheduled publishing" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Gallery Ads" name="enableGalleryAds" valuePropName="checked" extra="Promotional cards inserted into the public video gallery" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Events (Gancio)" name="enableEvents" valuePropName="checked" extra="Event calendar integration (requires gancio container)" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Docs Collaboration" name="enableDocsCollaboration" valuePropName="checked" extra="Real-time collaborative editing in the documentation editor" style={{ marginBottom: 0 }}>
                  <Switch />
                </Form.Item>
              </Card>
            </Col>

            {/* Communication */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><MessageOutlined /> Communication</Space>}
              >
                <Form.Item label="Team Chat (Rocket.Chat)" name="enableChat" valuePropName="checked" extra="Team coordination chat (requires rocketchat container)" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Video Meetings (Jitsi)" name="enableMeet" valuePropName="checked" extra="Self-hosted video calls — integrates with Rocket.Chat channels" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="SMS Campaigns" name="enableSms" valuePropName="checked" extra="Termux Android SMS for campaign texting and conversations" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Meeting Planner" name="enableMeetingPlanner" valuePropName="checked" extra="Scheduling polls for finding the best meeting time" style={{ marginBottom: 0 }}>
                  <Switch />
                </Form.Item>
              </Card>
            </Col>

            {/* People & Engagement */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><TeamOutlined /> People & Engagement</Space>}
              >
                <Form.Item label="People CRM" name="enablePeople" valuePropName="checked" extra="Unified contacts, connections, and engagement tracking" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Social Connections" name="enableSocial" valuePropName="checked" extra="Volunteer friend connections, activity feeds, and discovery" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Social Calendar" name="enableSocialCalendar" valuePropName="checked" extra="Personal calendar with layers, shared views, and .ics integration" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Auto-sync People to Map" name="autoSyncPeopleToMap" valuePropName="checked" extra="Adding a contact address auto-creates a map location with geocoding" style={{ marginBottom: 0 }}>
                  <Switch />
                </Form.Item>
              </Card>
            </Col>

            {/* Commerce */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><DollarOutlined /> Commerce</Space>}
              >
                <Form.Item label="Payments (Stripe)" name="enablePayments" valuePropName="checked" extra="Subscriptions, products, and donations" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Ticketed Events" name="enableTicketedEvents" valuePropName="checked" extra="Create events with tiered tickets, QR check-in, and Stripe payments" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Require Event Approval" name="requireEventApproval" valuePropName="checked" extra="Non-admin users need admin approval before publishing events" style={{ marginBottom: 0 }}>
                  <Switch />
                </Form.Item>
              </Card>
            </Col>

            {/* Analytics */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><BarChartOutlined /> Analytics</Space>}
              >
                <Form.Item label="Analytics Dashboard" name="enableAnalytics" valuePropName="checked" extra="Unified cross-module analytics with geo-tracking" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="GeoIP Tracking" name="analyticsGeoEnabled" valuePropName="checked" extra="Resolve visitor locations from IP addresses (requires MaxMind credentials in .env)" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Track Authenticated Users" name="trackAuthenticatedUsers" valuePropName="checked" extra="Include logged-in user activity in analytics" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Retention (days)" name="analyticsRetentionDays" extra="Auto-delete analytics data older than this (7-365)" style={{ marginBottom: 0 }}>
                  <InputNumber min={7} max={365} style={{ width: '100%' }} />
                </Form.Item>
              </Card>
            </Col>
          </Row>
        </div>
      ),
    },
    {
      key: 'notifications',
      label: 'Notifications',
      children: (
        <div>
          <Alert
            type="info"
            message="Control which automated email notifications are sent. Disabling a notification stops future emails but does not affect existing queued jobs."
            showIcon
            style={{ marginBottom: 24 }}
          />
          <Row gutter={[16, 16]}>
            {/* Admin Alerts */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><AlertOutlined /> Admin Alerts</Space>}
              >
                <Form.Item label="New Shift Signup" name="notifyAdminShiftSignup" valuePropName="checked" extra="When a volunteer signs up for a shift" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Response Wall Submission" name="notifyAdminResponseSubmitted" valuePropName="checked" extra="When a new response is submitted for moderation" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Sign Request" name="notifyAdminSignRequested" valuePropName="checked" extra="When a resident requests a yard sign during canvassing" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Shift Cancellation" name="notifyAdminShiftCancellation" valuePropName="checked" extra="When a volunteer cancels their shift signup" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Petition Milestones" name="notifyAdminPetitionMilestone" valuePropName="checked" extra="When a petition reaches a signature milestone (100, 500, 1000, etc.)" style={{ marginBottom: 0 }}>
                  <Switch />
                </Form.Item>
              </Card>
            </Col>

            {/* Volunteer Emails */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><MailOutlined /> Volunteer Emails</Space>}
              >
                <Form.Item label="Canvass Session Summary" name="notifyVolunteerSessionSummary" valuePropName="checked" extra="Summary email after completing a canvassing session" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Signup Cancellation" name="notifyVolunteerCancellation" valuePropName="checked" extra="Confirmation when their shift signup is cancelled" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="24h Pre-Shift Reminder" name="notifyVolunteerShiftReminder" valuePropName="checked" extra="Reminder email 24 hours before their shift" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Post-Shift Thank You" name="notifyVolunteerShiftThankYou" valuePropName="checked" extra="Thank-you email 2 hours after their shift ends" style={{ marginBottom: 0 }}>
                  <Switch />
                </Form.Item>
              </Card>
            </Col>

            {/* Re-Engagement */}
            <Col xs={24} lg={12}>
              <Card
                size="small"
                title={<Space><RetweetOutlined /> Volunteer Re-Engagement</Space>}
              >
                <Form.Item label="Re-Engagement Emails" name="notifyVolunteerReengagement" valuePropName="checked" extra="Automatically email inactive volunteers" style={{ marginBottom: 12 }}>
                  <Switch />
                </Form.Item>
                <Form.Item label="Inactive After (days)" name="reengagementInactiveDays" extra="Days without activity before considered inactive" style={{ marginBottom: 12 }}>
                  <InputNumber min={1} max={365} />
                </Form.Item>
                <Form.Item label="Cooldown Period (days)" name="reengagementCooldownDays" extra="Minimum days between re-engagement emails" style={{ marginBottom: 0 }}>
                  <InputNumber min={1} max={365} />
                </Form.Item>
              </Card>
            </Col>

            {/* SMS Notifications — only show when enableSms is on */}
            <Form.Item noStyle shouldUpdate={(prev: Record<string, unknown>, cur: Record<string, unknown>) => prev.enableSms !== cur.enableSms}>
              {({ getFieldValue }: { getFieldValue: (name: string) => unknown }) =>
                getFieldValue('enableSms') ? (
                  <Col xs={24} lg={12}>
                    <Card
                      size="small"
                      title={<Space><PhoneOutlined /> SMS Notifications</Space>}
                    >
                      <Form.Item label="Shift Reminders" name="smsShiftReminders" valuePropName="checked" extra="SMS reminder before a volunteer's shift. Variables: {name}, {shiftTitle}, {shiftTime}, {shiftLocation}" style={{ marginBottom: 12 }}>
                        <Switch />
                      </Form.Item>
                      <Form.Item label="Reminder Hours Before" name="smsShiftReminderHours" extra="Hours before shift to send the SMS reminder (1-72)" style={{ marginBottom: 12 }}>
                        <InputNumber min={1} max={72} />
                      </Form.Item>
                      <Form.Item label="Signup Confirmations" name="smsShiftSignupConfirm" valuePropName="checked" extra="SMS confirmation when a volunteer signs up. Variables: {name}, {shiftTitle}, {shiftDate}, {shiftTime}" style={{ marginBottom: 12 }}>
                        <Switch />
                      </Form.Item>
                      <Form.Item label="Volunteer Welcome" name="smsVolunteerWelcome" valuePropName="checked" extra="Welcome SMS when a new volunteer account is created. Variables: {name}" style={{ marginBottom: 12 }}>
                        <Switch />
                      </Form.Item>
                      <Text type="secondary" style={{ fontSize: 12, display: 'block' }}>
                        All SMS notifications respect opt-outs. Requires an active phone connection.
                      </Text>
                    </Card>
                  </Col>
                ) : null
              }
            </Form.Item>
          </Row>
        </div>
      ),
    },
    {
      key: 'system',
      label: 'System',
      icon: <CloudSyncOutlined />,
      children: <div data-tour-settings-domains><SystemUpgradeTab /></div>,
    },
  ];

  return (
    <Form form={form} layout="vertical">
      <Tabs items={items} defaultActiveKey={locationState?.activeTab || 'organization'} size={isMobile ? 'small' : 'middle'} />
      <div style={{ marginTop: 24 }}>
        <Button type="primary" icon={<SaveOutlined />} size="large" onClick={handleSave}>
          Save Settings
        </Button>
      </div>
      <PageTour sectionId="settings" />
    </Form>
  );
}

// =============================================================================
// System Upgrade Tab
// =============================================================================

const UPGRADE_PHASES = [
  'Pre-flight Checks',
  'Backup',
  'Code Update',
  'Container Rebuild',
  'Service Restart',
  'Verification',
];

function SystemUpgradeTab() {
  const { settings, updateSettings } = useSettingsStore();
  const [status, setStatus] = useState<UpgradeStatus | null>(null);
  const [progress, setProgress] = useState<UpgradeProgress | null>(null);
  const [result, setResult] = useState<UpgradeResult | null>(null);
  const [running, setRunning] = useState(false);
  const [watcher, setWatcher] = useState<WatcherHealth | null>(null);
  // Breaking-release gate: operator must type the target tag to confirm.
  // Resets whenever the remoteCommit changes so we re-prompt on every new
  // breaking release instead of carrying stale confirmation state.
  const [breakingConfirmInput, setBreakingConfirmInput] = useState('');
  const [checking, setChecking] = useState(false);
  const [upgrading, setUpgrading] = useState(false);
  const [apiOffline, setApiOffline] = useState(false);
  const [confirmOpen, setConfirmOpen] = useState(false);
  const [skipBackup, setSkipBackup] = useState(false);
  const [pullServices, setPullServices] = useState(false);
  const [useRegistry, setUseRegistry] = useState(false);
  const [history, setHistory] = useState<UpgradeResult[]>([]);
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const checkStartRef = useRef<string | null>(null);

  const fetchStatus = useCallback(async () => {
    try {
      const { data } = await api.get<UpgradeStatusResponse>('/upgrade/status');
      setStatus(data.status);
      setProgress(data.progress);
      setResult(data.result);
      setRunning(data.running);
      setWatcher(data.watcher ?? null);
      setApiOffline(false);
      return data;
    } catch {
      setApiOffline(true);
      return null;
    }
  }, []);

  const fetchHistory = useCallback(async () => {
    try {
      const { data } = await api.get<UpgradeHistoryResponse>('/upgrade/history');
      setHistory(data.history || []);
    } catch {
      // Ignore — history is non-critical
    }
  }, []);

  // Initial fetch on mount
  useEffect(() => {
    fetchStatus().then((data) => {
      // If already running when we load, start polling
      if (data?.running) {
        setUpgrading(true);
        startUpgradePoll();
      }
    });
    fetchHistory();
    return () => stopPoll();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Reset breaking-release typed confirmation whenever the target release
  // changes — otherwise a stale confirm from a previous release body could
  // carry over into a new breaking upgrade.
  useEffect(() => {
    setBreakingConfirmInput('');
  }, [status?.remoteCommit]);

  const stopPoll = () => {
    if (pollRef.current) {
      clearInterval(pollRef.current);
      pollRef.current = null;
    }
  };

  const startCheckPoll = () => {
    stopPoll();
    checkStartRef.current = status?.checkedAt || null;
    pollRef.current = setInterval(async () => {
      const data = await fetchStatus();
      if (!data) return;
      // Check complete when checkedAt changes
      if (data.status && data.status.checkedAt !== checkStartRef.current) {
        setChecking(false);
        stopPoll();
        message.success('Update check complete');
      }
    }, 2000);
    // Auto-stop after 30s (idempotent — harmless if check already completed)
    setTimeout(() => {
      setChecking(false);
      stopPoll();
    }, 30000);
  };

  const startUpgradePoll = () => {
    stopPoll();
    pollRef.current = setInterval(async () => {
      const data = await fetchStatus();
      // If API is offline, show restarting message (expected during upgrade)
      if (!data) return;
      // Upgrade complete when result appears or not running anymore
      if (data.result && !data.running) {
        setUpgrading(false);
        stopPoll();
        fetchHistory(); // Refresh history after upgrade
        if (data.result.success) {
          message.success('Upgrade completed successfully');
        } else {
          message.error('Upgrade failed');
        }
      }
    }, 3000);
  };

  const handleCheckForUpdates = async () => {
    setChecking(true);
    try {
      await api.post('/upgrade/check');
      startCheckPoll();
    } catch {
      setChecking(false);
      message.error('Failed to trigger update check');
    }
  };

  const handleStartUpgrade = async () => {
    setConfirmOpen(false);
    setUpgrading(true);
    setResult(null);
    try {
      await api.post('/upgrade/start', { skipBackup, pullServices, useRegistry });
      startUpgradePoll();
    } catch {
      setUpgrading(false);
      message.error('Failed to trigger upgrade');
    }
  };

  const handleClearResult = async () => {
    try {
      await api.post('/upgrade/clear-result');
      setResult(null);
    } catch {
      message.error('Failed to clear result');
    }
  };

  const handleAutoUpgradeToggle = async (field: string, value: unknown) => {
    try {
      await updateSettings({ [field]: value });
    } catch {
      message.error('Failed to save auto-upgrade settings');
    }
  };

  const formatDate = (dateStr: string) => {
    try {
      return new Date(dateStr).toLocaleString();
    } catch {
      return dateStr;
    }
  };

  const formatDuration = (seconds: number) => {
    const m = Math.floor(seconds / 60);
    const s = seconds % 60;
    return m > 0 ? `${m}m ${s}s` : `${s}s`;
  };

  const formatRelativeTime = (dateStr: string) => {
    const diff = Date.now() - new Date(dateStr).getTime();
    const mins = Math.floor(diff / 60000);
    if (mins < 1) return 'just now';
    if (mins < 60) return `${mins}m ago`;
    const hours = Math.floor(mins / 60);
    if (hours < 24) return `${hours}h ago`;
    const days = Math.floor(hours / 24);
    return `${days}d ago`;
  };

  const isUpgrading = upgrading || running;
  const autoUpgradeEnabled = settings?.enableAutoUpgrade ?? false;

  return (
    <div style={{ maxWidth: 800 }}>
      {/* Current Version */}
      <Card
        size="small"
        title={<Space><BranchesOutlined /> Current Version</Space>}
        style={{ marginBottom: 16 }}
      >
        {status ? (
          <Descriptions column={{ xs: 1, sm: 2 }} size="small">
            <Descriptions.Item label="Branch">
              <Tag color="blue">{status.branch}</Tag>
            </Descriptions.Item>
            <Descriptions.Item label="Commit">
              <Text code>{status.currentCommit}</Text>
            </Descriptions.Item>
            <Descriptions.Item label="Last Commit Message" span={2}>
              <Text>{status.currentMessage}</Text>
            </Descriptions.Item>
            <Descriptions.Item label="Commit Date">
              {status.currentDate ? formatDate(status.currentDate) : '-'}
            </Descriptions.Item>
            <Descriptions.Item label="Last Checked">
              {status.checkedAt ? (
                <Text type="secondary">{formatRelativeTime(status.checkedAt)}</Text>
              ) : (
                <Text type="secondary">Never</Text>
              )}
            </Descriptions.Item>
          </Descriptions>
        ) : (
          <Paragraph type="secondary">
            No version information available. Click "Check for Updates" to fetch the current status.
          </Paragraph>
        )}
      </Card>

      {/* Available Updates */}
      {status && status.commitsBehind > 0 && (
        <Card
          size="small"
          title={
            <Space>
              <HistoryOutlined />
              Available Updates
              <Tag color="orange">{status.commitsBehind} commit{status.commitsBehind !== 1 ? 's' : ''} behind</Tag>
            </Space>
          }
          style={{ marginBottom: 16 }}
        >
          <div style={{ maxHeight: 240, overflowY: 'auto' }}>
            <Timeline
              items={status.changelog.map((entry) => ({
                color: status.breaking ? 'red' : 'blue',
                children: (
                  <div>
                    <Space size={4}>
                      <Text code style={{ fontSize: 12 }}>{entry.hash}</Text>
                      <Text type="secondary" style={{ fontSize: 12 }}>{entry.author}</Text>
                      {status.breaking && <Tag color="red">BREAKING</Tag>}
                    </Space>
                    <div><Text style={{ fontSize: 13 }}>{entry.message}</Text></div>
                  </div>
                ),
              }))}
            />
          </div>
        </Card>
      )}

      {status && status.commitsBehind === 0 && status.checkedAt && !status.error && (
        <Alert
          type="success"
          message="Up to date"
          description={`Your installation is on the latest commit (${status.currentCommit}) of the ${status.branch} branch.`}
          showIcon
          style={{ marginBottom: 16 }}
        />
      )}

      {status?.error && (
        <Alert
          type="error"
          message="Update check failed"
          description={status.error}
          showIcon
          style={{ marginBottom: 16 }}
        />
      )}

      {watcher && !watcher.healthy && (
        <Alert
          type="warning"
          message="Upgrade watcher stalled"
          description={
            <>
              <div>{watcher.reason || 'Host systemd watcher is not processing upgrade triggers.'}</div>
              <div style={{ marginTop: 8 }}>
                Recovery:{' '}
                <Text code>
                  sudo systemctl reset-failed changemaker-upgrade.path changemaker-upgrade.service && sudo systemctl restart changemaker-upgrade.path
                </Text>
              </div>
            </>
          }
          showIcon
          style={{ marginBottom: 16 }}
        />
      )}

      {/* Breaking-release gate: requires typed target tag to confirm.
          Auto-upgrade refuses to fire when status.breaking is true. */}
      {status?.breaking && status.commitsBehind > 0 && (
        <Alert
          type="error"
          message={<Space>⚠️ Breaking release — manual confirmation required</Space>}
          description={
            <>
              <Paragraph style={{ marginBottom: 8 }}>
                <Text strong>{status.remoteCommit}</Text> is flagged as breaking:{' '}
                <Text italic>{status.breakingReason || 'No reason provided.'}</Text>
              </Paragraph>
              <Paragraph style={{ marginBottom: 8 }} type="secondary">
                Auto-upgrade will not apply this release. Type the target tag below to confirm you've
                reviewed the release notes and backed up any at-risk data before proceeding.
              </Paragraph>
              <Input
                placeholder={`Type "${status.remoteCommit}" to confirm`}
                value={breakingConfirmInput}
                onChange={(e) => setBreakingConfirmInput(e.target.value)}
                style={{ maxWidth: 320 }}
              />
            </>
          }
          showIcon
          style={{ marginBottom: 16 }}
        />
      )}

      {/* Actions */}
      <Space style={{ marginBottom: 16 }}>
        <Button
          icon={checking ? <LoadingOutlined /> : <SyncOutlined />}
          loading={checking}
          onClick={handleCheckForUpdates}
          disabled={isUpgrading}
        >
          Check for Updates
        </Button>
        <Button
          type="primary"
          icon={<RocketOutlined />}
          onClick={() => setConfirmOpen(true)}
          disabled={
            isUpgrading ||
            !status ||
            status.commitsBehind === 0 ||
            // Breaking releases require the operator to type the exact target
            // tag. Prevents accidental Start Upgrade clicks on dangerous releases.
            (!!status.breaking && breakingConfirmInput.trim() !== (status.remoteCommit || ''))
          }
        >
          Start Upgrade
        </Button>
      </Space>

      {/* Upgrade Progress */}
      {isUpgrading && (
        <Card
          size="small"
          title={<Space><LoadingOutlined spin /> Upgrade in Progress</Space>}
          style={{ marginBottom: 16 }}
        >
          {apiOffline ? (
            <Alert
              type="warning"
              message="Services restarting..."
              description="The API is temporarily offline while containers are being rebuilt. This is expected. The page will automatically reconnect."
              showIcon
              icon={<ReloadOutlined spin />}
              style={{ marginBottom: 12 }}
            />
          ) : progress ? (
            <>
              <Steps
                size="small"
                current={progress.phase - 1}
                items={UPGRADE_PHASES.map((name, i) => ({
                  title: name,
                  status: progress.phase - 1 > i ? 'finish' : progress.phase - 1 === i ? 'process' : 'wait',
                }))}
                style={{ marginBottom: 16 }}
              />
              <Progress percent={progress.percentage} status="active" />
              <Paragraph type="secondary" style={{ marginTop: 8, marginBottom: 0 }}>
                {progress.message}
              </Paragraph>
            </>
          ) : (
            <div style={{ textAlign: 'center', padding: 20 }}>
              <Spin />
              <Paragraph type="secondary" style={{ marginTop: 8, marginBottom: 0 }}>
                Waiting for upgrade to start...
              </Paragraph>
            </div>
          )}
        </Card>
      )}

      {/* Last Result */}
      {result && !isUpgrading && (
        <Card
          size="small"
          title={<Space><HistoryOutlined /> Last Upgrade Result</Space>}
          extra={
            <Button size="small" type="text" onClick={handleClearResult}>
              Dismiss
            </Button>
          }
          style={{ marginBottom: 16 }}
        >
          <Alert
            type={result.success ? 'success' : 'error'}
            message={result.success ? 'Upgrade Successful' : 'Upgrade Failed'}
            description={result.message}
            showIcon
            style={{ marginBottom: 12 }}
          />
          <Descriptions column={{ xs: 1, sm: 2 }} size="small">
            <Descriptions.Item label="Previous">
              <Text code>{result.previousCommit}</Text>
            </Descriptions.Item>
            <Descriptions.Item label="Current">
              <Text code>{result.newCommit}</Text>
            </Descriptions.Item>
            <Descriptions.Item label="Commits">
              {result.commitCount}
            </Descriptions.Item>
            <Descriptions.Item label="Duration">
              {formatDuration(result.durationSeconds)}
            </Descriptions.Item>
            <Descriptions.Item label="Completed">
              {formatDate(result.completedAt)}
            </Descriptions.Item>
          </Descriptions>
          {result.warnings.length > 0 && (
            <Alert
              type="warning"
              message="Warnings"
              description={
                <ul style={{ margin: 0, paddingLeft: 20 }}>
                  {result.warnings.map((w, i) => <li key={i}>{w}</li>)}
                </ul>
              }
              showIcon
              style={{ marginTop: 12 }}
            />
          )}
        </Card>
      )}

      {/* Auto-Upgrade Configuration */}
      <Card
        size="small"
        title={<Space><ClockCircleOutlined /> Auto-Upgrade</Space>}
        style={{ marginBottom: 16 }}
      >
        <Space direction="vertical" style={{ width: '100%' }} size={12}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <Switch
              checked={autoUpgradeEnabled}
              onChange={(v) => handleAutoUpgradeToggle('enableAutoUpgrade', v)}
            />
            <Text>Enable automatic upgrades</Text>
          </div>
          {autoUpgradeEnabled && (
            <>
              <div>
                <Text type="secondary" style={{ display: 'block', marginBottom: 4 }}>Schedule</Text>
                <Select
                  value={settings?.autoUpgradeSchedule || 'daily-3am'}
                  onChange={(v) => handleAutoUpgradeToggle('autoUpgradeSchedule', v)}
                  style={{ width: 220 }}
                  options={[
                    { label: 'Daily at 3:00 AM', value: 'daily-3am' },
                    { label: 'Daily at 4:00 AM', value: 'daily-4am' },
                    { label: 'Daily at 5:00 AM', value: 'daily-5am' },
                    { label: 'Weekly (Sunday 3 AM)', value: 'weekly-sun-3am' },
                    { label: 'Weekly (Monday 3 AM)', value: 'weekly-mon-3am' },
                    { label: 'Every 12 hours', value: '12h' },
                    { label: 'Every 24 hours', value: '24h' },
                  ]}
                />
              </div>
              <Checkbox
                checked={settings?.autoUpgradePullServices ?? false}
                onChange={(e) => handleAutoUpgradeToggle('autoUpgradePullServices', e.target.checked)}
              >
                Also pull third-party Docker images (PostgreSQL, Redis, etc.)
              </Checkbox>
              <Checkbox
                checked={settings?.notifyAdminAutoUpgrade ?? true}
                onChange={(e) => handleAutoUpgradeToggle('notifyAdminAutoUpgrade', e.target.checked)}
              >
                Email admins on auto-upgrade completion or failure
              </Checkbox>
            </>
          )}
        </Space>
      </Card>

      {/* Container Registry */}
      <Card
        size="small"
        title={<Space><CloudSyncOutlined /> Container Registry</Space>}
        style={{ marginBottom: 16 }}
      >
        <Space direction="vertical" style={{ width: '100%' }} size={12}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <Switch
              checked={settings?.useRegistryForUpgrade ?? false}
              onChange={(v) => handleAutoUpgradeToggle('useRegistryForUpgrade', v)}
            />
            <div>
              <Text>Use Gitea registry for upgrades</Text>
              <br />
              <Text type="secondary" style={{ fontSize: 12 }}>
                Pull pre-built production images instead of compiling from source. Faster upgrades.
                Requires <Text code style={{ fontSize: 12 }}>scripts/build-and-push.sh</Text> to have been run first.
              </Text>
            </div>
          </div>
          {settings?.useRegistryForUpgrade && (
            <div>
              <Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 2 }}>
                Registry URL
              </Text>
              <Text code style={{ fontSize: 12 }}>
                {settings?.giteaRegistryUrl || 'gitea.bnkops.com/admin'}
              </Text>
            </div>
          )}
        </Space>
      </Card>

      {/* Recent Commits Feed */}
      {status?.changelog && status.changelog.length > 0 && status.commitsBehind === 0 && (
        <Card
          size="small"
          title={<Space><BranchesOutlined /> Recent Commits</Space>}
          style={{ marginBottom: 16 }}
        >
          <div style={{ maxHeight: 300, overflowY: 'auto' }}>
            <Timeline
              items={status.changelog.map((entry) => ({
                color: 'gray',
                children: (
                  <div>
                    <Space size={4}>
                      <Text code style={{ fontSize: 12 }}>{entry.hash}</Text>
                      <Text type="secondary" style={{ fontSize: 12 }}>{entry.author}</Text>
                      {entry.date && (
                        <Text type="secondary" style={{ fontSize: 12 }}>{formatRelativeTime(entry.date)}</Text>
                      )}
                    </Space>
                    <div><Text style={{ fontSize: 13 }}>{entry.message}</Text></div>
                  </div>
                ),
              }))}
            />
          </div>
        </Card>
      )}

      {/* Upgrade History */}
      {history.length > 0 && (
        <Card
          size="small"
          title={<Space><HistoryOutlined /> Upgrade History</Space>}
          style={{ marginBottom: 16 }}
        >
          <div style={{ maxHeight: 300, overflowY: 'auto' }}>
            <Timeline
              items={history.map((entry, i) => ({
                color: entry.success ? 'green' : 'red',
                children: (
                  <div key={i}>
                    <Space size={4} wrap>
                      <Tag color={entry.success ? 'success' : 'error'} style={{ fontSize: 11 }}>
                        {entry.success ? 'Success' : 'Failed'}
                      </Tag>
                      <Text code style={{ fontSize: 12 }}>{entry.previousCommit}</Text>
                      <Text type="secondary" style={{ fontSize: 12 }}>→</Text>
                      <Text code style={{ fontSize: 12 }}>{entry.newCommit}</Text>
                      <Text type="secondary" style={{ fontSize: 12 }}>
                        {formatRelativeTime(entry.completedAt)}
                      </Text>
                      {entry.triggeredBy && (
                        <Tag style={{ fontSize: 11 }}>
                          {entry.triggeredBy === 'auto-upgrade' ? 'auto' : entry.triggeredBy}
                        </Tag>
                      )}
                    </Space>
                    <div>
                      <Text style={{ fontSize: 13 }}>{entry.message}</Text>
                      {entry.commitCount > 0 && (
                        <Text type="secondary" style={{ fontSize: 12 }}> ({entry.commitCount} commit{entry.commitCount !== 1 ? 's' : ''}, {formatDuration(entry.durationSeconds)})</Text>
                      )}
                    </div>
                    {entry.warnings.length > 0 && (
                      <div style={{ marginTop: 4 }}>
                        {entry.warnings.map((w, wi) => (
                          <Text key={wi} type="warning" style={{ fontSize: 12, display: 'block' }}>{w}</Text>
                        ))}
                      </div>
                    )}
                  </div>
                ),
              }))}
            />
          </div>
        </Card>
      )}

      {/* Systemd Setup Info */}
      <Card
        size="small"
        title={<Space><InfoCircleOutlined /> Setup</Space>}
        style={{ marginBottom: 16, opacity: 0.8 }}
      >
        <Paragraph type="secondary" style={{ marginBottom: 8 }}>
          The upgrade system requires a systemd path watcher on the host. This is normally
          installed by <Text code>./config.sh</Text> during initial setup. To install or
          reinstall manually:
        </Paragraph>
        <Paragraph code copyable style={{ fontSize: 12, marginBottom: 0 }}>
          {`cd ~/changemaker.lite && sudo ./scripts/systemd/install.sh`}
        </Paragraph>
      </Card>

      {/* Upgrade Confirmation Modal */}
      <Modal
        title={
          <Space>
            <ExclamationCircleOutlined style={{ color: '#faad14' }} />
            Confirm System Upgrade
          </Space>
        }
        open={confirmOpen}
        onOk={handleStartUpgrade}
        onCancel={() => setConfirmOpen(false)}
        okText="Start Upgrade"
        okButtonProps={{ danger: true }}
      >
        <Paragraph>
          This will pull the latest code, rebuild containers, and restart all services.
          The admin panel will be briefly unavailable during the restart.
        </Paragraph>
        {status && (
          <Paragraph>
            <Text strong>{status.commitsBehind}</Text> commit{status.commitsBehind !== 1 ? 's' : ''} will
            be applied from <Text code>{status.currentCommit}</Text> to <Text code>{status.remoteCommit}</Text>.
          </Paragraph>
        )}
        <Divider style={{ margin: '12px 0' }} />
        <Space direction="vertical">
          <Checkbox
            checked={pullServices}
            onChange={(e) => setPullServices(e.target.checked)}
          >
            Pull third-party images (PostgreSQL, Redis, etc.)
          </Checkbox>
          <Checkbox
            checked={skipBackup}
            onChange={(e) => setSkipBackup(e.target.checked)}
          >
            <Text type="danger">Skip backup (not recommended)</Text>
          </Checkbox>
          <Checkbox
            checked={useRegistry}
            onChange={(e) => setUseRegistry(e.target.checked)}
          >
            Use registry images (faster — needs build-and-push.sh run first)
          </Checkbox>
        </Space>
      </Modal>
    </div>
  );
}

function Swatch({ label, color }: { label: string; color: string }) {
  return (
    <div style={{ textAlign: 'center' }}>
      <div
        style={{
          width: 48,
          height: 48,
          borderRadius: 8,
          background: color,
          border: '2px solid rgba(255,255,255,0.2)',
          marginBottom: 4,
        }}
      />
      <Text style={{ fontSize: 11 }}>{label}</Text>
    </div>
  );
}

/** Parse "linear-gradient(135deg, #005a9c 0%, #007acc 100%)" into parts */
function parseGradient(val: string): { angle: number; color1: string; color2: string } {
  const defaults = { angle: 135, color1: '#005a9c', color2: '#007acc' };
  if (!val || !val.includes('linear-gradient')) return defaults;
  const inner = val.replace(/^linear-gradient\(/, '').replace(/\)$/, '');
  // Match angle
  const angleMatch = inner.match(/^(\d+)deg/);
  const angle = angleMatch ? parseInt(angleMatch[1]!, 10) : defaults.angle;
  // Match colors (hex, rgb, named)
  const colorMatches = inner.match(/#[0-9a-fA-F]{3,8}|rgba?\([^)]+\)/g);
  return {
    angle,
    color1: colorMatches?.[0] ?? defaults.color1,
    color2: colorMatches?.[1] ?? colorMatches?.[0] ?? defaults.color2,
  };
}

function buildGradient(angle: number, color1: string, color2: string): string {
  return `linear-gradient(${angle}deg, ${color1} 0%, ${color2} 100%)`;
}

/** Custom form control — accepts value/onChange from Form.Item */
function GradientPicker({ value, onChange }: { value?: string; onChange?: (val: string) => void }) {
  const parsed = parseGradient(value || '');
  const [angle, setAngle] = useState(parsed.angle);
  const [color1, setColor1] = useState(parsed.color1);
  const [color2, setColor2] = useState(parsed.color2);

  // Sync from external value changes (e.g., form reset)
  useEffect(() => {
    const p = parseGradient(value || '');
    setAngle(p.angle);
    setColor1(p.color1);
    setColor2(p.color2);
  }, [value]);

  const emit = useCallback(
    (a: number, c1: string, c2: string) => {
      onChange?.(buildGradient(a, c1, c2));
    },
    [onChange],
  );

  const gradient = buildGradient(angle, color1, color2);

  return (
    <div>
      {/* Live preview */}
      <div
        style={{
          background: gradient,
          borderRadius: 8,
          padding: '16px 24px',
          color: '#fff',
          fontWeight: 600,
          fontSize: 14,
          marginBottom: 16,
          border: '1px solid rgba(255,255,255,0.1)',
        }}
      >
        Header Gradient Preview
      </div>

      {/* Color pickers row */}
      <div style={{ display: 'flex', gap: 16, alignItems: 'center', flexWrap: 'wrap', marginBottom: 12 }}>
        <div>
          <Text style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>Start Color</Text>
          <ColorPicker
            value={color1}
            format="hex"
            showText
            onChange={(_val, hex) => {
              setColor1(hex);
              emit(angle, hex, color2);
            }}
          />
        </div>
        <div>
          <Text style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>End Color</Text>
          <ColorPicker
            value={color2}
            format="hex"
            showText
            onChange={(_val, hex) => {
              setColor2(hex);
              emit(angle, color1, hex);
            }}
          />
        </div>
        <Button
          size="small"
          onClick={() => {
            setColor1(color2);
            setColor2(color1);
            emit(angle, color2, color1);
          }}
          style={{ marginTop: 18 }}
        >
          Swap
        </Button>
      </div>

      {/* Angle slider */}
      <div style={{ marginBottom: 8 }}>
        <Text style={{ fontSize: 12 }}>Angle: {angle}°</Text>
        <Slider
          min={0}
          max={360}
          value={angle}
          onChange={(val) => {
            setAngle(val);
            emit(val, color1, color2);
          }}
          tooltip={{ formatter: (v) => `${v}°` }}
          styles={{ track: { background: gradient } }}
        />
      </div>

      {/* Raw CSS output (editable) */}
      <Input
        size="small"
        value={gradient}
        onChange={(e) => {
          const raw = e.target.value;
          onChange?.(raw);
          const p = parseGradient(raw);
          setAngle(p.angle);
          setColor1(p.color1);
          setColor2(p.color2);
        }}
        style={{ fontFamily: 'monospace', fontSize: 12 }}
      />
    </div>
  );
}
