/* ============================================================
   Bizia — Hosting & Publish  (/app/infrastructure)
   Hosting choice, deploy status, URLs, rollback, publish.
   ============================================================ */
(function () {
  const { useState, useEffect } = React;
  const { Card, Badge, Button, Icon, PageHeader, StatusBadge, Modal } = window;

  function HostingPage() {
    const data = window.DATA;
    const [selected, setSelected] = useState('cloudflare');
    const [publishOpen, setPublishOpen] = useState(false);
    const [published, setPublished] = useState(false);
    const [publishing, setPublishing] = useState(false);

    const [jobId, setJobId] = useState(null);
    const [project, setProject] = useState(null);
    const [historyList, setHistoryList] = useState([]);
    const [checklist, setChecklist] = useState(data.checklist);
    const [liveUrl, setLiveUrl] = useState(null);
    const [deployMode, setDeployMode] = useState(null); // 'real' | 'demo' | null

    // Hash-routed SPA — the ?project= query string lives inside
    // window.location.hash, not window.location.search (which is always
    // empty here). Reading .search silently fell back to a mock project.
    const projectId = new URLSearchParams(window.location.hash.split('?')[1] || '').get('project') || data.projects?.[0]?.id;

    useEffect(() => {
      if (!projectId) return;
      window.API.projects.get(projectId).then(p => { if (p) setProject(p); }).catch(() => {});
      window.API.publish.history(projectId).then(hist => { if (Array.isArray(hist)) setHistoryList(hist); }).catch(() => {});
      window.API.seo.checklist(projectId).then(list => { if (list && list.length) setChecklist(list); }).catch(() => {});
    }, [projectId]);

    function timeAgo(iso) {
      if (!iso) return 'never';
      const ms = Date.now() - new Date(iso).getTime();
      const mins = Math.round(ms / 60000);
      if (mins < 1) return 'just now';
      if (mins < 60) return mins + 'm ago';
      const hrs = Math.round(mins / 60);
      if (hrs < 24) return hrs + 'h ago';
      return Math.round(hrs / 24) + 'd ago';
    }
    const lastJob = historyList[0];
    const buildSeconds = lastJob ? Math.max(0, Math.round((new Date(lastJob.updatedAt) - new Date(lastJob.createdAt)) / 1000)) : null;
    const previewUrl = project?.previewUrl || (projectId ? `/api/preview/${projectId}/` : '—');
    const prodUrl = project?.productionUrl || (project?.pagesSubdomain ? `${project.pagesSubdomain}.pages.dev` : 'Not deployed yet');

    useEffect(() => {
      if (!jobId) return;
      const iv = setInterval(() => {
        window.API.publish.status(jobId).then(status => {
          if (status?.status === 'done' || status?.status === 'success' || status?.status === 'failed') {
            clearInterval(iv);
            setPublishing(false);
            if (status.status === 'done' || status.status === 'success') {
              // resultJson comes over the wire as a JSON string (see
              // PublishJob.resultJson in schema.prisma), not an object.
              let result = {};
              try { result = typeof status.resultJson === 'string' ? JSON.parse(status.resultJson) : (status.resultJson || {}); } catch { result = {}; }
              const url = result.url || null;
              const mock = result.mock ?? true;
              setLiveUrl(url);
              setDeployMode(mock ? 'demo' : 'real');
              setPublished(true);
              window.toast({ title: 'Published!', desc: url || 'Your site is live.', tone: 'success' });
            } else window.toast({ title: 'Publish failed', desc: status.error || 'Try again.', tone: 'danger' });
          }
        }).catch(() => {});
      }, 3000);
      return () => clearInterval(iv);
    }, [jobId]);

    async function doPublish() {
      if (!projectId) {
        window.toast({ title: 'No project selected', desc: 'Open Hosting & Publish from a specific project.', tone: 'danger' });
        return;
      }
      setPublishing(true);
      try {
        // startPublishJob (backend) returns { jobId, ... } — not { id }.
        // Reading job.id (undefined) meant setJobId(undefined) never
        // started the polling effect below, so the modal stayed on
        // "Publishing…" forever even when the job completed successfully.
        const job = await window.API.publish.start({ projectId, provider: selected });
        setJobId(job.jobId);
      } catch (e) {
        setPublishing(false);
        window.toast({ title: 'Cannot publish yet', desc: e.message || 'Publish was blocked.', tone: 'danger' });
      }
    }

    const doneCount = checklist.filter(c => c.status === 'done').length;

    return React.createElement('div', { className: 'bz-anim-up' },
      React.createElement(PageHeader, {
        icon: 'rocket', title: 'Hosting & Publish',
        sub: 'Bizia puts your website on fast, secure servers and handles deployment. Review hosting, then publish to go live.',
        actions: React.createElement(Button, { variant: 'primary', icon: 'rocket', onClick: () => setPublishOpen(true) }, published ? 'Published' : 'Publish website'),
      }),

      React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'minmax(0,1.5fr) minmax(0,1fr)', gap: 16, alignItems: 'start' }, className: 'bz-host-grid' },
        React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 16 } },
          // deployment status
          React.createElement(Card, { pad: 0, style: { overflow: 'hidden' } },
            React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 13, padding: '18px 20px', borderBottom: '1px solid var(--border-soft)', background: 'var(--surface-2)' } },
              React.createElement('div', { style: { width: 42, height: 42, borderRadius: 11, background: 'var(--secondary-soft)', color: 'var(--secondary)', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, React.createElement(Icon, { name: 'cloud', size: 22 })),
              React.createElement('div', { style: { flex: 1 } },
                React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 9 } }, React.createElement('span', { style: { fontSize: 16, fontWeight: 650 } }, 'Cloudflare Pages'), React.createElement(StatusBadge, { status: published ? 'published' : (lastJob ? 'ready' : 'off'), label: published ? 'Live' : (lastJob ? 'Deployed' : 'Not deployed yet'), size: 'sm' })),
                React.createElement('div', { style: { fontSize: 12.5, color: 'var(--muted)', marginTop: 2 } }, lastJob ? ('Last deploy ' + timeAgo(lastJob.createdAt) + (buildSeconds != null ? ' · build ' + buildSeconds + 's' : '')) : 'No deploys yet')),
              React.createElement(Button, { variant: 'outline', size: 'sm', icon: 'refresh', onClick: () => window.toast({ title: 'Redeploying', desc: 'Building latest changes…', tone: 'primary' }) }, 'Redeploy'),
            ),
            React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(200px,1fr))' } },
              [['eye', 'Preview URL', previewUrl, 'Always-on staging'], ['globe', 'Production URL', published ? prodUrl : prodUrl + ' (pending)', published ? 'Live to the world' : 'Goes live on publish']].map((u, i) =>
                React.createElement('div', { key: i, style: { padding: '16px 20px', borderRight: i === 0 ? '1px solid var(--border-soft)' : 'none' } },
                  React.createElement('div', { style: { fontSize: 11.5, color: 'var(--muted)', fontWeight: 600, display: 'flex', alignItems: 'center', gap: 6 } }, React.createElement(Icon, { name: u[0], size: 13 }), u[1]),
                  React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 } },
                    React.createElement('span', { style: { fontSize: 13.5, fontWeight: 600, fontFamily: 'var(--font-mono)', color: i === 1 && !published ? 'var(--muted)' : 'var(--text)' } }, u[2]),
                    React.createElement('button', { onClick: () => window.toast({ title: 'Copied', tone: 'info' }), style: { border: 'none', background: 'none', cursor: 'pointer', color: 'var(--muted)', display: 'flex' } }, React.createElement(Icon, { name: 'copy', size: 14 }))),
                  React.createElement('div', { style: { fontSize: 11.5, color: 'var(--muted-2)', marginTop: 4 } }, u[3]))),
            ),
          ),
          // choose hosting
          React.createElement(Card, { pad: 22 },
            React.createElement('h3', { style: { fontSize: 16, fontWeight: 650, marginBottom: 4 } }, 'Where your website lives'),
            React.createElement('p', { style: { fontSize: 13.5, color: 'var(--muted)', marginBottom: 16 } }, 'Bizia picked the best option for you. Most businesses never need to change this.'),
            React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(220px,1fr))', gap: 12 } },
              data.hostingOptions.map(h => {
                const sel = selected === h.id; const [bg, fg] = window.BZ_TONES[h.tone];
                return React.createElement('button', { key: h.id, onClick: () => setSelected(h.id),
                  style: { textAlign: 'left', padding: 16, borderRadius: 'var(--r-md)', cursor: 'pointer', background: sel ? 'var(--primary-soft)' : 'var(--surface-2)', border: '1.5px solid ' + (sel ? 'var(--primary)' : 'var(--border)') } },
                  React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
                    React.createElement('div', { style: { width: 34, height: 34, borderRadius: 9, background: bg, color: fg, display: 'flex', alignItems: 'center', justifyContent: 'center' } }, React.createElement(Icon, { name: h.logo, size: 17 })),
                    h.recommended ? React.createElement(Badge, { tone: 'secondary', size: 'sm' }, 'Recommended') : sel ? React.createElement(Icon, { name: 'checkcircle', size: 18, style: { color: 'var(--primary)' } }) : null),
                  React.createElement('div', { style: { fontSize: 14.5, fontWeight: 650, marginTop: 11 } }, h.name),
                  React.createElement('div', { style: { fontSize: 12, color: 'var(--muted)', lineHeight: 1.45, marginTop: 5 } }, h.why),
                  React.createElement('div', { style: { fontSize: 13, fontWeight: 700, marginTop: 10, color: 'var(--secondary)' } }, h.cost));
              }),
            ),
          ),
          // deployment history
          React.createElement(Card, { pad: 22 },
            React.createElement('h3', { style: { fontSize: 15.5, fontWeight: 650, marginBottom: 14 } }, 'Deployment history'),
            React.createElement('div', { style: { display: 'flex', flexDirection: 'column' } },
              historyList.length === 0
                ? React.createElement('div', { style: { padding: '20px 0', fontSize: 13, color: 'var(--muted)', textAlign: 'center' } }, 'No deployments yet.')
                : historyList.map((h, i) => React.createElement('div', { key: h.id, style: { display: 'flex', alignItems: 'center', gap: 12, padding: '12px 0', borderBottom: i < historyList.length - 1 ? '1px solid var(--border-soft)' : 'none' } },
                    React.createElement('div', { style: { width: 28, height: 28, borderRadius: 8, background: h.status === 'failed' ? 'var(--danger-soft, #fdecea)' : 'var(--success-soft)', color: h.status === 'failed' ? 'var(--danger)' : 'var(--success)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, React.createElement(Icon, { name: h.status === 'failed' ? 'x' : 'check', size: 15 })),
                    React.createElement('div', { style: { flex: 1, minWidth: 0 } },
                      React.createElement('div', { style: { fontSize: 13.5, fontWeight: 550 } }, h.status === 'success' ? 'Published successfully' : h.status === 'failed' ? 'Publish failed' : h.status === 'running' ? 'Publishing…' : h.status),
                      React.createElement('div', { style: { fontSize: 12, color: 'var(--muted)' } }, h.createdAt ? new Date(h.createdAt).toLocaleString() : '')))),
            ),
          ),
        ),
        // right column
        React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 16 } },
          // publish checklist
          React.createElement(Card, { pad: 20 },
            React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 } },
              React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } }, React.createElement(Icon, { name: 'checklist', size: 17, style: { color: 'var(--primary)' } }), React.createElement('h4', { style: { fontSize: 15, fontWeight: 650 } }, 'Publish checklist')),
              React.createElement('span', { style: { fontSize: 12.5, fontWeight: 600, color: 'var(--muted)' } }, doneCount + '/' + checklist.length)),
            React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 1 } },
              checklist.map(c => {
                const done = c.status === 'done', prog = c.status === 'in-progress';
                return React.createElement('div', { key: c.id, style: { display: 'flex', gap: 11, padding: '9px 0', borderBottom: '1px solid var(--border-soft)' } },
                  React.createElement('div', { style: { width: 20, height: 20, borderRadius: 999, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: done ? 'var(--secondary)' : prog ? 'var(--accent-soft)' : 'var(--surface-3)', color: done ? '#fff' : 'var(--accent)', marginTop: 1 } },
                    done ? React.createElement(Icon, { name: 'check', size: 12 }) : prog ? React.createElement('span', { style: { width: 6, height: 6, borderRadius: 999, background: 'var(--accent)' } }) : null),
                  React.createElement('div', { style: { flex: 1, minWidth: 0 } },
                    React.createElement('div', { style: { fontSize: 13, fontWeight: 550, color: done ? 'var(--muted)' : 'var(--text)' } }, c.label),
                    React.createElement('div', { style: { fontSize: 11.5, color: 'var(--muted-2)' } }, c.simple)),
                  c.optional ? React.createElement('span', { style: { fontSize: 10.5, color: 'var(--muted-2)', flexShrink: 0 } }, 'Optional') : null);
              }),
            ),
            React.createElement(Button, { variant: 'primary', full: true, icon: 'rocket', style: { marginTop: 14 }, onClick: () => setPublishOpen(true) }, published ? 'Published' : 'Publish website'),
          ),
          // env vars
          React.createElement(Card, { pad: 20 },
            React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 } },
              React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } }, React.createElement(Icon, { name: 'key', size: 16, style: { color: 'var(--muted)' } }), React.createElement('h4', { style: { fontSize: 14.5, fontWeight: 650 } }, 'Environment variables')),
              React.createElement(Badge, { tone: 'neutral', size: 'sm' }, 'Advanced')),
            React.createElement('p', { style: { fontSize: 12.5, color: 'var(--muted)', lineHeight: 1.5, marginBottom: 12 } }, 'Connect API keys and secrets when you add integrations. None needed for a basic site.'),
            React.createElement('div', { style: { fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--muted)', padding: 12, borderRadius: 'var(--r-sm)', background: 'var(--surface-3)', border: '1px solid var(--border-soft)' } }, 'No variables set'),
            React.createElement(Button, { variant: 'ghost', size: 'sm', icon: 'plus', full: true, style: { marginTop: 10 }, onClick: () => window.toast({ title: 'Add variable', desc: 'Available when you connect services.', tone: 'info' }) }, 'Add variable'),
          ),
        ),
      ),

      React.createElement(Modal, { open: publishOpen, onClose: () => !publishing && setPublishOpen(false), width: 440 },
        published ? React.createElement('div', { style: { textAlign: 'center', padding: '12px 0' } },
          React.createElement('div', { style: { width: 60, height: 60, borderRadius: 18, background: 'var(--success-soft)', color: 'var(--success)', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 16px' } }, React.createElement(Icon, { name: 'checkcircle', size: 32 })),
          React.createElement('h2', { style: { fontSize: 22, fontWeight: 720 } }, "You're live!"),
          React.createElement('p', { style: { fontSize: 14, color: 'var(--muted)', marginTop: 8 } }, 'Your website is now published at'),
          liveUrl ? React.createElement('a', { href: liveUrl, target: '_blank', rel: 'noopener noreferrer', style: { display: 'block', fontSize: 15, fontWeight: 700, fontFamily: 'var(--font-mono)', color: 'var(--primary-700)', margin: '8px 0 4px', wordBreak: 'break-all' } }, liveUrl)
            : React.createElement('div', { style: { fontSize: 15, fontWeight: 700, fontFamily: 'var(--font-mono)', color: 'var(--muted)', margin: '8px 0 4px' } }, 'URL loading…'),
          deployMode ? React.createElement('div', { style: { fontSize: 11.5, color: deployMode === 'demo' ? 'var(--muted-2)' : 'var(--success)', marginBottom: 18 } },
            deployMode === 'demo' ? 'Demo mode — set CLOUDFLARE_API_TOKEN to deploy for real' : 'Deployed via Cloudflare Pages')
            : null,
          React.createElement('div', { style: { display: 'flex', gap: 10, marginTop: 8 } },
            liveUrl
              ? React.createElement('a', { href: liveUrl, target: '_blank', rel: 'noopener noreferrer', style: { flex: 1, textDecoration: 'none' } },
                  React.createElement(Button, { variant: 'outline', icon: 'externalLink', full: true }, 'Open live site'))
              : React.createElement(Button, { variant: 'outline', icon: 'externalLink', style: { flex: 1 }, onClick: () => window.toast({ title: 'URL not available yet', tone: 'info' }) }, 'Open live site'),
            React.createElement(Button, { variant: 'primary', icon: 'search', style: { flex: 1 }, onClick: () => { setPublishOpen(false); window.navigate('/app/seo'); } }, 'Set up Google')),
        ) : React.createElement('div', null,
          React.createElement('div', { style: { width: 52, height: 52, borderRadius: 14, background: 'var(--primary-soft)', color: 'var(--primary-700)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 16 } }, React.createElement(Icon, { name: 'rocket', size: 26 })),
          React.createElement('h2', { style: { fontSize: 21, fontWeight: 700 } }, 'Publish your website'),
          React.createElement('p', { style: { fontSize: 14, color: 'var(--muted)', marginTop: 8, lineHeight: 1.5 } }, 'This will deploy your latest changes to Cloudflare Pages and make it visible to everyone.'),
          React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, margin: '18px 0' } },
            ['All pages built & reviewed', 'Domain connected & secure', 'SEO & sitemap ready'].map((t, i) => React.createElement('div', { key: i, style: { display: 'flex', alignItems: 'center', gap: 9, fontSize: 13.5 } }, React.createElement(Icon, { name: 'checkcircle', size: 16, style: { color: 'var(--secondary)' } }), t))),
          React.createElement('div', { style: { display: 'flex', gap: 10 } },
            React.createElement(Button, { variant: 'ghost', onClick: () => setPublishOpen(false), style: { flex: 1 }, disabled: publishing }, 'Cancel'),
            React.createElement(Button, { variant: 'primary', icon: publishing ? null : 'rocket', style: { flex: 1 }, onClick: doPublish, disabled: publishing },
              publishing ? React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 8 } }, React.createElement('span', { style: { width: 14, height: 14, border: '2px solid rgba(255,255,255,0.5)', borderTopColor: '#fff', borderRadius: 999, animation: 'bz-spin .7s linear infinite' } }), 'Publishing…') : 'Publish now')),
        ),
      ),
      React.createElement('style', null, '@media(max-width:900px){.bz-host-grid{grid-template-columns:1fr !important}}'),
    );
  }

  window.HostingPage = HostingPage;
})();
