import { useState, useEffect } from 'react';
import { Plus, Trash2, Edit, Eye, Shield, Copy, Download, Key, AlertTriangle, CheckCircle, Globe, Lock, Users, Server } from 'lucide-react';
import { peerRegistryAPI, wireguardAPI, cellLinkAPI, getCsrfToken } from '../services/api';
import { useConfig } from '../contexts/ConfigContext';
import QRCode from 'qrcode';

const FULL_TUNNEL_IPS = '0.0.0.0/0, ::/0';

const emptyForm = () => ({
  name: '',
  description: '',
  public_key: '',
  persistent_keepalive: 25,
  internet_access: true,
  service_access: ['calendar', 'files', 'mail', 'webdav'],
  peer_access: true,
  create_calendar: false,
  password: '',
});

const generatePassword = () => {
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%';
  const arr = new Uint8Array(14);
  crypto.getRandomValues(arr);
  return Array.from(arr).map(b => chars[b % chars.length]).join('');
};

function AccessBadge({ icon: Icon, label, active }) {
  return (
    <span className={`inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium mr-1 ${
      active ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-400'
    }`}>
      <Icon className="h-3 w-3 mr-0.5" />
      {label}
    </span>
  );
}

function Toggle({ checked, onChange, label, description }) {
  return (
    <label className="flex items-start gap-3 cursor-pointer">
      <div className="relative mt-0.5">
        <input type="checkbox" className="sr-only" checked={checked} onChange={e => onChange(e.target.checked)} />
        <div className={`w-10 h-6 rounded-full transition-colors ${checked ? 'bg-primary-600' : 'bg-gray-300'}`} />
        <div className={`absolute top-1 left-1 w-4 h-4 rounded-full bg-white shadow transition-transform ${checked ? 'translate-x-4' : ''}`} />
      </div>
      <div>
        <div className="text-sm font-medium text-gray-900">{label}</div>
        {description && <div className="text-xs text-gray-500 mt-0.5">{description}</div>}
      </div>
    </label>
  );
}

function Peers() {
  const { domain = 'cell' } = useConfig();
  const SERVICES = [
    { key: 'calendar', label: 'Calendar', domain: `calendar.${domain}` },
    { key: 'files',    label: 'Files',    domain: `files.${domain}` },
    { key: 'mail',     label: 'Webmail',  domain: `mail.${domain}` },
    { key: 'webdav',   label: 'WebDAV',   domain: `webdav.${domain}` },
  ];

  const [peers, setPeers] = useState([]);
  const [connectedCells, setConnectedCells] = useState([]);
  const [serverConf, setServerConf] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [showAddModal, setShowAddModal] = useState(false);
  const [showEditModal, setShowEditModal] = useState(false);
  const [showViewModal, setShowViewModal] = useState(false);
  const [selectedPeer, setSelectedPeer] = useState(null);
  const [formData, setFormData] = useState(emptyForm());
  const [showAdvanced, setShowAdvanced] = useState(false);
  const [peerConfig, setPeerConfig] = useState('');
  const [qrCodeDataUrl, setQrCodeDataUrl] = useState('');
  const [isGeneratingKeys, setIsGeneratingKeys] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errors, setErrors] = useState({});
  const [toast, setToast] = useState(null);

  useEffect(() => {
    fetchPeers();
    cellLinkAPI.listConnections().then(r => setConnectedCells(r.data || [])).catch(() => {});
  }, []);

  const showToast = (msg, type = 'success') => {
    setToast({ msg, type });
    setTimeout(() => setToast(null), 4000);
  };

  const fetchPeers = async () => {
    try {
      const [regResp, statusResp, scResp] = await Promise.all([
        peerRegistryAPI.getPeers(),
        wireguardAPI.getPeerStatuses().catch(() => ({ data: {} })),
        fetch('/api/wireguard/server-config', { credentials: 'include' }).then(r => r.ok ? r.json() : null).catch(() => null),
      ]);
      const regPeers = regResp.data || [];
      const statusMap = statusResp.data || {};
      const merged = regPeers.map(p => ({
        ...p,
        name: p.peer || p.name,
        online: statusMap[p.public_key]?.online ?? false,
        last_handshake: statusMap[p.public_key]?.last_handshake ?? null,
        last_handshake_seconds_ago: statusMap[p.public_key]?.last_handshake_seconds_ago ?? null,
        transfer_rx: statusMap[p.public_key]?.transfer_rx ?? 0,
        transfer_tx: statusMap[p.public_key]?.transfer_tx ?? 0,
      }));
      setPeers(merged);
      if (scResp) setServerConf(scResp);
    } catch (err) {
      console.error('Failed to fetch peers:', err);
    } finally {
      setIsLoading(false);
    }
  };

  const getServerConfig = async () => {
    if (serverConf) return serverConf;
    try {
      const r = await fetch('/api/wireguard/server-config', { credentials: 'include' });
      if (r.ok) {
        const sc = await r.json();
        setServerConf(sc);
        return sc;
      }
    } catch {}
    return { public_key: 'SERVER_PUBLIC_KEY_PLACEHOLDER', endpoint: 'YOUR_SERVER_IP:51820' };
  };

  const generateConfig = (peer, sc) => {
    const privateKey = peer.private_key || 'YOUR_PRIVATE_KEY_HERE';
    const serverPubKey = peer.server_public_key || sc?.public_key || 'SERVER_PUBLIC_KEY_PLACEHOLDER';
    const endpoint = peer.server_endpoint || sc?.endpoint || 'YOUR_SERVER_IP:51820';
    const address = peer.ip?.includes('/') ? peer.ip : `${peer.ip}/32`;
    const splitTunnelIPs = sc?.split_tunnel_ips || `10.0.0.0/24`;
    const allowedIPs = peer.internet_access !== false ? FULL_TUNNEL_IPS : splitTunnelIPs;
    const dnsIp = sc?.dns_ip || '10.0.0.1';
    return `[Interface]
PrivateKey = ${privateKey}
Address = ${address}
DNS = ${dnsIp}

[Peer]
PublicKey = ${serverPubKey}
Endpoint = ${endpoint}
AllowedIPs = ${allowedIPs}
PersistentKeepalive = ${peer.persistent_keepalive || 25}`;
  };

  const generateKeys = async () => {
    if (!formData.name) { setErrors(e => ({ ...e, name: 'Enter a name first' })); return; }
    setIsGeneratingKeys(true);
    try {
      const r = await wireguardAPI.generatePeerKeys({ peer_name: formData.name });
      setFormData(f => ({ ...f, public_key: r.data.public_key, _private_key: r.data.private_key }));
    } catch { showToast('Failed to generate keys', 'error'); }
    finally { setIsGeneratingKeys(false); }
  };

  const validate = (data) => {
    const errs = {};
    if (!data.name.trim()) errs.name = 'Name is required';
    if (!/^[a-zA-Z0-9_-]+$/.test(data.name)) errs.name = 'Only letters, numbers, - and _ allowed';
    return errs;
  };

  const handleAddPeer = async (e) => {
    e.preventDefault();
    const errs = validate(formData);
    if (!formData.password || formData.password.length < 10) errs.password = 'Password must be at least 10 characters';
    if (Object.keys(errs).length) { setErrors(errs); return; }
    setIsSubmitting(true);
    try {
      let publicKey = formData.public_key;
      let privateKey = formData._private_key || null;
      if (!publicKey) {
        const kr = await wireguardAPI.generatePeerKeys({ peer_name: formData.name });
        publicKey = kr.data.public_key;
        privateKey = kr.data.private_key;
      }
      const serverConf = await getServerConfig();
      const peerData = {
        name: formData.name,
        ip: formData.ip,
        public_key: publicKey,
        private_key: privateKey,
        server_public_key: serverConf.public_key,
        server_endpoint: serverConf.endpoint,
        persistent_keepalive: formData.persistent_keepalive,
        description: formData.description,
        internet_access: formData.internet_access,
        service_access: formData.service_access,
        peer_access: formData.peer_access,
        password: formData.password,
      };
      const addResult = await peerRegistryAPI.addPeer(peerData);

      if (formData.create_calendar) {
        try {
          await fetch(`/api/calendar/create-user-collection?user=${formData.name}`, {
            method: 'POST',
            credentials: 'include',
            headers: { 'X-CSRF-Token': getCsrfToken() || '' },
          });
        } catch {}
      }

      const provisioned = addResult.data?.provisioned;
      const createdName = formData.name;
      const provisionedList = provisioned
        ? Object.entries(provisioned).filter(([, v]) => v).map(([k]) => k).join(', ')
        : '';
      setShowAddModal(false);
      setFormData(emptyForm());
      setErrors({});
      fetchPeers();
      showToast(
        `Peer "${createdName}" created.` + (provisionedList ? ` Accounts: ${provisionedList}.` : ''),
        'success'
      );
    } catch (err) {
      showToast(err?.response?.data?.error || 'Failed to add peer', 'error');
    } finally { setIsSubmitting(false); }
  };

  const handleUpdatePeer = async (e) => {
    e.preventDefault();
    const errs = validate(formData);
    if (Object.keys(errs).length) { setErrors(errs); return; }
    setIsSubmitting(true);
    try {
      const r = await fetch(`/api/peers/${selectedPeer.name}`, {
        method: 'PUT',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrfToken() || '' },
        body: JSON.stringify({
          description: formData.description,
          internet_access: formData.internet_access,
          service_access: formData.service_access,
          peer_access: formData.peer_access,
          persistent_keepalive: formData.persistent_keepalive,
        }),
      });
      const result = await r.json();

      // Server-side AllowedIPs for the peer must stay as /32 (host route only)
      const existingIp = selectedPeer.ip?.includes('/') ? selectedPeer.ip : `${selectedPeer.ip}/32`;
      await wireguardAPI.addPeer({
        name: selectedPeer.name,
        public_key: formData.public_key || selectedPeer.public_key,
        allowed_ips: existingIp,
        persistent_keepalive: formData.persistent_keepalive,
      });

      // Route-via is a separate endpoint (triggers WG + iptables changes)
      const oldRouteVia = selectedPeer.route_via || null;
      const newRouteVia = formData.route_via || null;
      if (oldRouteVia !== newRouteVia) {
        await peerRegistryAPI.setRouteVia(selectedPeer.name, newRouteVia);
      }

      setShowEditModal(false);
      setSelectedPeer(null);
      fetchPeers();
      if (result.config_changed) {
        showToast(`Peer updated. Config changed — ask them to reinstall the tunnel.`, 'warning');
      } else {
        showToast('Peer updated successfully.');
      }
    } catch (err) {
      showToast('Failed to update peer', 'error');
    } finally { setIsSubmitting(false); }
  };

  const handleRemovePeer = async (peerName) => {
    if (!window.confirm(`Remove peer "${peerName}"?`)) return;
    try {
      await peerRegistryAPI.removePeer(peerName);
      fetchPeers();
      showToast(`Peer "${peerName}" removed.`);
    } catch { showToast('Failed to remove peer', 'error'); }
  };

  const handleViewPeer = async (peer) => {
    setSelectedPeer(peer);
    setQrCodeDataUrl('');
    setPeerConfig('');
    setShowViewModal(true);
    try {
      const serverConf = await getServerConfig();
      let config;
      try {
        const r = await wireguardAPI.getPeerConfig({ name: peer.name });
        config = r.data.config;
      } catch {}
      if (!config || config.includes('PLACEHOLDER')) {
        config = generateConfig({ ...peer, server_public_key: serverConf.public_key, server_endpoint: serverConf.endpoint }, serverConf);
      }
      setPeerConfig(config);
      const qr = await QRCode.toDataURL(config, { width: 256, margin: 2, errorCorrectionLevel: 'M' });
      setQrCodeDataUrl(qr);
    } catch (err) {
      console.error('Failed to load peer config:', err);
    }
  };

  const handleConfigDownloaded = async (peerName) => {
    try {
      await fetch(`/api/peers/${peerName}/clear-reinstall`, {
        method: 'POST',
        credentials: 'include',
        headers: { 'X-CSRF-Token': getCsrfToken() || '' },
      });
      setPeers(ps => ps.map(p => p.name === peerName ? { ...p, config_needs_reinstall: false } : p));
    } catch {}
  };

  const handleEditPeer = (peer) => {
    setSelectedPeer(peer);
    setFormData({
      name: peer.name,
      ip: peer.ip || '',
      description: peer.description || '',
      public_key: peer.public_key || '',
      persistent_keepalive: peer.persistent_keepalive || 25,
      internet_access: peer.internet_access !== false,
      service_access: peer.service_access || ['calendar', 'files', 'mail', 'webdav'],
      peer_access: peer.peer_access !== false,
      create_calendar: false,
      route_via: peer.route_via || null,
    });
    setErrors({});
    setShowAdvanced(false);
    setShowEditModal(true);
  };

  const toggleService = (key) => {
    setFormData(f => ({
      ...f,
      service_access: f.service_access.includes(key)
        ? f.service_access.filter(s => s !== key)
        : [...f.service_access, key],
    }));
  };

  const copyToClipboard = async (text) => {
    try { await navigator.clipboard.writeText(text); showToast('Copied to clipboard!'); }
    catch { showToast('Copy failed', 'error'); }
  };

  const downloadConfig = (peerName, config) => {
    const blob = new Blob([config], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = `${peerName}.conf`;
    document.body.appendChild(a); a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    if (selectedPeer) handleConfigDownloaded(selectedPeer.name);
  };

  const AccessForm = ({ data, onChange }) => (
    <div className="space-y-5 pt-4 border-t border-gray-200">
      <div>
        <div className="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-1.5">
          <Globe className="h-4 w-4" /> Internet Access
        </div>
        <div className="flex gap-2">
          <button type="button"
            onClick={() => onChange({ internet_access: true })}
            className={`flex-1 px-3 py-2 rounded border text-sm font-medium transition-colors ${data.internet_access ? 'bg-primary-600 text-white border-primary-600' : 'bg-white text-gray-600 border-gray-300 hover:border-primary-400'}`}>
            <Globe className="h-4 w-4 inline mr-1" />Full tunnel
            <div className="text-xs font-normal mt-0.5 opacity-75">All traffic via PIC server</div>
          </button>
          <button type="button"
            onClick={() => onChange({ internet_access: false })}
            className={`flex-1 px-3 py-2 rounded border text-sm font-medium transition-colors ${!data.internet_access ? 'bg-primary-600 text-white border-primary-600' : 'bg-white text-gray-600 border-gray-300 hover:border-primary-400'}`}>
            <Lock className="h-4 w-4 inline mr-1" />Split tunnel
            <div className="text-xs font-normal mt-0.5 opacity-75">Only PIC services via VPN</div>
          </button>
        </div>
      </div>

      <div>
        <div className="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-1.5">
          <Server className="h-4 w-4" /> Service Access
        </div>
        <div className="grid grid-cols-2 gap-2">
          {SERVICES.map(svc => (
            <label key={svc.key} className={`flex items-center gap-2 p-2.5 rounded border cursor-pointer transition-colors ${
              data.service_access?.includes(svc.key) ? 'bg-green-50 border-green-300' : 'bg-gray-50 border-gray-200'
            }`}>
              <input type="checkbox" className="rounded"
                checked={data.service_access?.includes(svc.key) ?? true}
                onChange={() => onChange({ service_access: data.service_access?.includes(svc.key)
                  ? data.service_access.filter(s => s !== svc.key)
                  : [...(data.service_access || []), svc.key]
                })} />
              <div>
                <div className="text-sm font-medium text-gray-900">{svc.label}</div>
                <div className="text-xs text-gray-500">{svc.domain}</div>
              </div>
            </label>
          ))}
        </div>
      </div>

      <div>
        <div className="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-1.5">
          <Users className="h-4 w-4" /> Peer Communication
        </div>
        <Toggle
          checked={data.peer_access !== false}
          onChange={v => onChange({ peer_access: v })}
          label="Allow peer-to-peer traffic"
          description={`This peer can communicate with other VPN peers (${serverConf?.vpn_network || 'VPN subnet'})`}
        />
      </div>

      {connectedCells.length > 0 && (
        <div>
          <div className="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-1.5">
            <Globe className="h-4 w-4" /> Internet Exit
          </div>
          <select
            value={data.route_via || ''}
            onChange={e => onChange({ route_via: e.target.value || null })}
            className="input"
          >
            <option value="">Direct (this cell's connection)</option>
            {connectedCells.map(cell => (
              <option key={cell.cell_name} value={cell.cell_name}>
                Via {cell.cell_name}
                {cell.remote_exit_offered ? ' ✓ offers internet' : ''}
              </option>
            ))}
          </select>
          <p className="text-xs text-gray-400 mt-1">
            Route this peer's internet traffic through a connected cell.
            {data.route_via && !connectedCells.find(c => c.cell_name === data.route_via)?.remote_exit_offered && (
              <span className="text-yellow-600 ml-1">The selected cell hasn't offered their internet yet.</span>
            )}
          </p>
        </div>
      )}
    </div>
  );

  if (isLoading) return (
    <div className="flex items-center justify-center h-64">
      <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600"></div>
    </div>
  );

  return (
    <div>
      {/* Toast */}
      {toast && (
        <div className={`fixed top-4 right-4 z-50 px-4 py-3 rounded-lg shadow-lg text-sm font-medium flex items-center gap-2 ${
          toast.type === 'error' ? 'bg-red-600 text-white' :
          toast.type === 'warning' ? 'bg-yellow-500 text-white' : 'bg-green-600 text-white'
        }`}>
          {toast.type === 'error' ? <AlertTriangle className="h-4 w-4" /> : <CheckCircle className="h-4 w-4" />}
          {toast.msg}
        </div>
      )}

      <div className="mb-8 flex justify-between items-center">
        <div>
          <h1 className="text-2xl font-bold text-gray-900">Peers</h1>
          <p className="mt-1 text-gray-600">Manage VPN peer connections and access policies</p>
        </div>
        <button onClick={() => { setFormData(emptyForm()); setErrors({}); setShowAdvanced(false); setShowAddModal(true); }}
          className="btn btn-primary flex items-center">
          <Plus className="h-4 w-4 mr-2" />Add Peer
        </button>
      </div>

      {/* Peers Table */}
      <div className="card">
        <div className="overflow-x-auto">
          <table className="min-w-full divide-y divide-gray-200">
            <thead className="bg-gray-50">
              <tr>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Peer</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">IP</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Access</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
                <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
              </tr>
            </thead>
            <tbody className="bg-white divide-y divide-gray-200">
              {peers.length === 0 ? (
                <tr><td colSpan="5" className="px-6 py-8 text-center text-gray-500">No peers configured.</td></tr>
              ) : peers.map(peer => (
                <tr key={peer.name} className="hover:bg-gray-50">
                  <td className="px-6 py-4">
                    <div className="flex items-center gap-2">
                      <Shield className="h-4 w-4 text-primary-500 flex-shrink-0" />
                      <div>
                        <div className="text-sm font-medium text-gray-900 flex items-center gap-1.5">
                          {peer.name}
                          {peer.config_needs_reinstall && (
                            <span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-800">
                              <AlertTriangle className="h-3 w-3" /> Reinstall tunnel
                            </span>
                          )}
                        </div>
                        {peer.description && <div className="text-xs text-gray-500">{peer.description}</div>}
                      </div>
                    </div>
                  </td>
                  <td className="px-6 py-4 text-sm text-gray-900 font-mono">{peer.ip}</td>
                  <td className="px-6 py-4">
                    <div className="flex flex-wrap gap-0.5">
                      <AccessBadge icon={Globe} label="Internet" active={peer.internet_access !== false} />
                      {SERVICES.map(s => (
                        <AccessBadge key={s.key} icon={Server} label={s.label} active={(peer.service_access || SERVICES.map(s=>s.key)).includes(s.key)} />
                      ))}
                      <AccessBadge icon={Users} label="Peers" active={peer.peer_access !== false} />
                      {peer.route_via && (
                        <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-700 mr-1">
                          <Globe className="h-3 w-3 mr-0.5" />via {peer.route_via}
                        </span>
                      )}
                    </div>
                  </td>
                  <td className="px-6 py-4">
                    <span className={`status-indicator ${peer.online ? 'status-online' : 'status-offline'}`}>
                      {peer.online ? 'Online' : 'Offline'}
                    </span>
                    {peer.last_handshake_seconds_ago != null && (
                      <div className="text-xs text-gray-400 mt-0.5">{peer.last_handshake_seconds_ago}s ago</div>
                    )}
                  </td>
                  <td className="px-6 py-4">
                    <div className="flex space-x-2">
                      <button onClick={() => handleViewPeer(peer)} className="text-primary-600 hover:text-primary-900" title="View Config & QR">
                        <Eye className="h-4 w-4" />
                      </button>
                      <button onClick={() => handleEditPeer(peer)} className="text-primary-600 hover:text-primary-900" title="Edit Peer">
                        <Edit className="h-4 w-4" />
                      </button>
                      <button onClick={() => handleRemovePeer(peer.name)} className="text-red-600 hover:text-red-900" title="Remove Peer">
                        <Trash2 className="h-4 w-4" />
                      </button>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      {/* Add Peer Modal */}
      {showAddModal && (
        <div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
          onClick={e => { if (e.target === e.currentTarget) setShowAddModal(false); }}>
          <div className="relative top-10 mx-auto p-6 border w-full max-w-lg shadow-lg rounded-md bg-white mb-10">
            <div className="flex items-center justify-between mb-4">
              <div className="flex items-center gap-2">
                <Shield className="h-6 w-6 text-primary-500" />
                <h3 className="text-lg font-medium text-gray-900">Add New Peer</h3>
              </div>
              <button onClick={() => setShowAddModal(false)} className="text-gray-400 hover:text-gray-600">✕</button>
            </div>
            <form onSubmit={handleAddPeer} className="space-y-4">
              <div className="grid grid-cols-2 gap-4">
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">Name *</label>
                  <input value={formData.name}
                    onChange={e => { setFormData(f => ({ ...f, name: e.target.value })); setErrors(e2 => ({ ...e2, name: undefined })); }}
                    className={`input ${errors.name ? 'border-red-500' : ''}`} placeholder="mobile-phone" />
                  {errors.name && <p className="text-xs text-red-600 mt-1">{errors.name}</p>}
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">Description</label>
                  <input value={formData.description} onChange={e => setFormData(f => ({ ...f, description: e.target.value }))}
                    className="input" placeholder="My laptop" />
                </div>
              </div>

              <AccessForm data={formData} onChange={updates => setFormData(f => ({ ...f, ...updates }))} />

              {/* Account Creation */}
              <div className="pt-3 border-t border-gray-200">
                <div className="text-sm font-semibold text-gray-700 mb-2">Account Setup</div>
                <div className="mb-3">
                  <label className="block text-sm font-medium text-gray-700 mb-1">Dashboard Password *</label>
                  <div className="flex gap-2">
                    <input
                      type="password"
                      value={formData.password}
                      onChange={e => { setFormData(f => ({ ...f, password: e.target.value })); setErrors(e2 => ({ ...e2, password: undefined })); }}
                      className={`input flex-1 ${errors.password ? 'border-red-500' : ''}`}
                      placeholder="Min 10 characters"
                      autoComplete="new-password"
                    />
                    <button type="button"
                      onClick={() => setFormData(f => ({ ...f, password: generatePassword() }))}
                      className="btn btn-secondary text-xs whitespace-nowrap">
                      Generate
                    </button>
                  </div>
                  {errors.password && <p className="text-xs text-red-600 mt-1">{errors.password}</p>}
                </div>
                <label className="flex items-center gap-2 cursor-pointer">
                  <input type="checkbox" checked={formData.create_calendar}
                    onChange={e => setFormData(f => ({ ...f, create_calendar: e.target.checked }))} className="rounded" />
                  <span className="text-sm text-gray-700">Create calendar collection for this peer</span>
                </label>
              </div>

              {/* Advanced */}
              <div className="pt-2 border-t border-gray-200">
                <button type="button" onClick={() => setShowAdvanced(!showAdvanced)}
                  className="text-sm text-primary-600 hover:text-primary-800 flex items-center gap-1">
                  <Key className="h-4 w-4" />
                  {showAdvanced ? 'Hide' : 'Show'} Advanced Options
                </button>
                {showAdvanced && (
                  <div className="mt-3 space-y-3">
                    <div>
                      <label className="block text-sm font-medium text-gray-700 mb-1">Public Key</label>
                      <div className="flex gap-2">
                        <textarea value={formData.public_key}
                          onChange={e => setFormData(f => ({ ...f, public_key: e.target.value }))}
                          className="input flex-1" rows="2" placeholder="Leave empty to auto-generate" />
                        <button type="button" onClick={generateKeys} disabled={isGeneratingKeys}
                          className="btn btn-secondary text-xs self-start mt-0.5">
                          {isGeneratingKeys ? '…' : 'Generate'}
                        </button>
                      </div>
                    </div>
                    <div>
                      <label className="block text-sm font-medium text-gray-700 mb-1">Keepalive (s)</label>
                      <input type="number" value={formData.persistent_keepalive} min="0" max="65535"
                        onChange={e => setFormData(f => ({ ...f, persistent_keepalive: parseInt(e.target.value) }))}
                        className="input w-32" />
                    </div>
                  </div>
                )}
              </div>

              <div className="flex justify-end gap-3 pt-2">
                <button type="button" onClick={() => setShowAddModal(false)} className="btn btn-secondary">Cancel</button>
                <button type="submit" disabled={isSubmitting} className="btn btn-primary flex items-center gap-2">
                  <Plus className="h-4 w-4" />{isSubmitting ? 'Adding…' : 'Add Peer'}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {/* Edit Peer Modal */}
      {showEditModal && selectedPeer && (
        <div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
          onClick={e => { if (e.target === e.currentTarget) { setShowEditModal(false); setSelectedPeer(null); } }}>
          <div className="relative top-10 mx-auto p-6 border w-full max-w-lg shadow-lg rounded-md bg-white mb-10">
            <div className="flex items-center justify-between mb-4">
              <div className="flex items-center gap-2">
                <Shield className="h-6 w-6 text-primary-500" />
                <h3 className="text-lg font-medium text-gray-900">Edit Peer — {selectedPeer.name}</h3>
              </div>
              <button onClick={() => { setShowEditModal(false); setSelectedPeer(null); }} className="text-gray-400 hover:text-gray-600">✕</button>
            </div>

            {selectedPeer.config_needs_reinstall && (
              <div className="mb-4 p-3 bg-yellow-50 border border-yellow-200 rounded-md flex items-start gap-2 text-sm text-yellow-800">
                <AlertTriangle className="h-4 w-4 flex-shrink-0 mt-0.5" />
                <div>Config changed since last tunnel install. After saving, download the updated config and reinstall on the device.</div>
              </div>
            )}

            <form onSubmit={handleUpdatePeer} className="space-y-4">
              <div className="grid grid-cols-2 gap-4">
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">Name</label>
                  <input value={formData.name} className="input bg-gray-50" disabled />
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">VPN IP</label>
                  <input value={selectedPeer?.ip || ''} className="input bg-gray-50 font-mono" disabled />
                </div>
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Description</label>
                <input value={formData.description} onChange={e => setFormData(f => ({ ...f, description: e.target.value }))} className="input" />
              </div>

              <AccessForm data={formData} onChange={updates => setFormData(f => ({ ...f, ...updates }))} />

              <div>
                <button type="button" onClick={() => setShowAdvanced(!showAdvanced)}
                  className="text-sm text-primary-600 hover:text-primary-800 flex items-center gap-1 mt-2">
                  <Key className="h-4 w-4" />
                  {showAdvanced ? 'Hide' : 'Show'} Advanced Options
                </button>
                {showAdvanced && (
                  <div className="mt-3">
                    <label className="block text-sm font-medium text-gray-700 mb-1">Keepalive (s)</label>
                    <input type="number" value={formData.persistent_keepalive} min="0" max="65535"
                      onChange={e => setFormData(f => ({ ...f, persistent_keepalive: parseInt(e.target.value) }))}
                      className="input w-32" />
                  </div>
                )}
              </div>

              <div className="flex justify-end gap-3 pt-2">
                <button type="button" onClick={() => { setShowEditModal(false); setSelectedPeer(null); }} className="btn btn-secondary">Cancel</button>
                <button type="submit" disabled={isSubmitting} className="btn btn-primary flex items-center gap-2">
                  <Edit className="h-4 w-4" />{isSubmitting ? 'Saving…' : 'Save Changes'}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {/* View Config Modal */}
      {showViewModal && selectedPeer && (
        <div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
          onClick={e => { if (e.target === e.currentTarget) setShowViewModal(false); }}>
          <div className="relative top-10 mx-auto p-6 border w-full max-w-4xl shadow-lg rounded-md bg-white mb-10">
            <div className="flex items-center justify-between mb-4">
              <div className="flex items-center gap-2">
                <Shield className="h-6 w-6 text-primary-500" />
                <h3 className="text-lg font-medium text-gray-900">{selectedPeer.name} — Tunnel Config</h3>
              </div>
              <button onClick={() => setShowViewModal(false)} className="text-gray-400 hover:text-gray-600">✕</button>
            </div>

            {selectedPeer.config_needs_reinstall && (
              <div className="mb-4 p-3 bg-yellow-50 border border-yellow-200 rounded-md flex items-start gap-2 text-sm text-yellow-800">
                <AlertTriangle className="h-4 w-4 flex-shrink-0 mt-0.5" />
                <div>
                  <strong>Config changed.</strong> Download the updated config below and reinstall the WireGuard tunnel on the device. The old config will no longer work correctly.
                </div>
              </div>
            )}

            <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-2">WireGuard Configuration File</label>
                {peerConfig ? (
                  <div className="relative">
                    <textarea value={peerConfig} readOnly
                      className="w-full h-64 p-3 border border-gray-300 rounded-md font-mono text-xs bg-gray-50" />
                    <div className="flex gap-2 mt-2">
                      <button onClick={() => copyToClipboard(peerConfig)}
                        className="btn btn-secondary btn-sm flex items-center gap-1">
                        <Copy className="h-4 w-4" /> Copy
                      </button>
                      <button onClick={() => downloadConfig(selectedPeer.name, peerConfig)}
                        className="btn btn-primary btn-sm flex items-center gap-1">
                        <Download className="h-4 w-4" /> Download .conf
                      </button>
                    </div>
                  </div>
                ) : (
                  <div className="h-64 bg-gray-50 rounded-md flex items-center justify-center text-gray-400 text-sm">
                    <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary-600 mr-2"></div>
                    Loading…
                  </div>
                )}
                <p className="text-xs text-gray-500 mt-2">
                  DNS is set to <code className="bg-gray-100 px-1 rounded">{serverConf?.dns_ip || '10.0.0.1'}</code> (PIC DNS) — required to resolve <code className="bg-gray-100 px-1 rounded">.{domain}</code> domains.
                </p>
              </div>

              <div>
                <label className="block text-sm font-medium text-gray-700 mb-2">QR Code — Scan with WireGuard app</label>
                <div className="text-center">
                  {qrCodeDataUrl ? (
                    <div className="space-y-3">
                      <div className="inline-block p-3 bg-white border-2 border-gray-200 rounded-lg">
                        <img src={qrCodeDataUrl} alt="WireGuard QR Code" className="w-48 h-48 mx-auto" />
                      </div>
                      <button onClick={() => { const a = document.createElement('a'); a.href = qrCodeDataUrl; a.download = `${selectedPeer.name}-qr.png`; a.click(); handleConfigDownloaded(selectedPeer.name); }}
                        className="btn btn-secondary btn-sm flex items-center gap-1 mx-auto">
                        <Download className="h-4 w-4" /> Download QR
                      </button>
                    </div>
                  ) : (
                    <div className="h-56 bg-gray-50 border-2 border-dashed border-gray-300 rounded-lg flex items-center justify-center text-gray-400 text-sm">
                      {peerConfig ? 'Generating QR…' : 'Loading…'}
                    </div>
                  )}
                </div>
              </div>
            </div>

            <div className="flex justify-between items-center mt-4 pt-4 border-t border-gray-200">
              <div className="text-xs text-gray-500">
                Tunnel: <span className="font-medium">{selectedPeer.internet_access !== false ? 'Full' : 'Split'}</span>
                {' · '}Services: <span className="font-medium">{(selectedPeer.service_access || SERVICES.map(s=>s.key)).join(', ')}</span>
              </div>
              <div className="flex gap-2">
                <button onClick={() => { setShowViewModal(false); handleEditPeer(selectedPeer); }} className="btn btn-secondary flex items-center gap-1">
                  <Edit className="h-4 w-4" /> Edit
                </button>
                <button onClick={() => setShowViewModal(false)} className="btn btn-secondary">Close</button>
              </div>
            </div>
          </div>
        </div>
      )}

    </div>
  );
}

export default Peers;
