import React, { FormEvent, useEffect, useMemo, useState } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';

type User = { id: number; name: string; email: string };
type Project = {
  id: number;
  title: string;
  description: string | null;
  status: 'ideia' | 'ativo' | 'pausado' | 'concluido' | 'abandonado';
  priority: 'baixa' | 'media' | 'alta';
  next_action: string | null;
  last_progress_at: string | null;
  due_date: string | null;
  stale_after_days: number;
  notes: string | null;
  days_stale?: number;
};
type Task = {
  id: number;
  project_id: number | null;
  project_title?: string | null;
  title: string;
  notes: string | null;
  due_at: string | null;
  completed_at: string | null;
  importance: 'baixa' | 'media' | 'alta';
  recurrence_rule: 'nenhuma' | 'diaria' | 'semanal' | 'mensal';
  email_reminder: number;
};
type StudyPlan = {
  id: number;
  title: string;
  objective: string | null;
  weekly_minutes: number;
  materials: string | null;
  progress: number;
  status: 'ativo' | 'pausado' | 'concluido';
  next_session_at: string | null;
};
type Settings = {
  email_to: string;
  alerts_enabled: number;
  digest_hour: number;
  timezone: string;
};
type Dashboard = {
  date: string;
  focusTasks: Task[];
  staleProjects: Project[];
  studyQueue: StudyPlan[];
  counts: { projects: number; tasks: number; study_plans: number };
};
type Review = {
  newProjects: Project[];
  completedTasks: Task[];
  overdueTasks: Task[];
  staleProjects: Project[];
};

type LoadErrors = Partial<Record<'dashboard' | 'projects' | 'tasks' | 'study' | 'settings' | 'review', string>>;

const emptyProject = {
  title: '',
  description: '',
  status: 'ideia',
  priority: 'media',
  next_action: '',
  last_progress_at: '',
  due_date: '',
  stale_after_days: 7,
  notes: '',
};

const emptyTask = {
  title: '',
  project_id: '',
  notes: '',
  due_at: '',
  importance: 'media',
  recurrence_rule: 'nenhuma',
  email_reminder: true,
};

const emptyStudy = {
  title: '',
  objective: '',
  weekly_minutes: 120,
  materials: '',
  progress: 0,
  status: 'ativo',
  next_session_at: '',
};

async function api<T>(path: string, options: RequestInit = {}): Promise<T> {
  const url = new URL(`${appBasePath()}api/${path}`, window.location.origin);
  const response = await fetch(url, {
    credentials: 'same-origin',
    headers: { 'Content-Type': 'application/json', ...(options.headers ?? {}) },
    ...options,
  });
  const payload = await response.json().catch(() => ({}));
  if (!response.ok) {
    throw new Error(payload.error ?? 'Erro inesperado.');
  }
  return payload as T;
}

function appBasePath(): string {
  const pathname = window.location.pathname;
  const publicIndex = pathname.indexOf('/public');

  if (publicIndex >= 0) {
    return `${pathname.slice(0, publicIndex + '/public'.length).replace(/\/$/, '')}/`;
  }

  return pathname.endsWith('/') ? pathname : `${pathname}/`;
}

function normalizeDateTime(value: string): string | null {
  if (!value) return null;
  return value.includes('T') ? `${value.replace('T', ' ')}:00` : value;
}

function formatDate(value?: string | null): string {
  if (!value) return 'Sem data';
  return value.replace('T', ' ').slice(0, 16);
}

function App() {
  const [booting, setBooting] = useState(true);
  const [hasUser, setHasUser] = useState(false);
  const [user, setUser] = useState<User | null>(null);

  useEffect(() => {
    Promise.all([
      api<{ hasUser: boolean }>('setup/status'),
      api<{ user: User | null }>('me').catch(() => ({ user: null })),
    ])
      .then(([setup, me]) => {
        setHasUser(setup.hasUser);
        setUser(me.user);
      })
      .finally(() => setBooting(false));
  }, []);

  if (booting) return <Splash />;
  if (!hasUser) return <SetupScreen onReady={(nextUser) => { setHasUser(true); setUser(nextUser); }} />;
  if (!user) return <LoginScreen onLogin={setUser} />;
  return <Workspace user={user} onLogout={() => setUser(null)} />;
}

function Splash() {
  return (
    <main className="auth-shell">
      <div className="brand-mark">PC</div>
      <p>Carregando seu painel...</p>
    </main>
  );
}

function SetupScreen({ onReady }: { onReady: (user: User) => void }) {
  const [form, setForm] = useState({ name: '', email: '', password: '' });
  const [error, setError] = useState('');

  async function submit(event: FormEvent) {
    event.preventDefault();
    setError('');
    try {
      const payload = await api<{ user: User }>('setup', { method: 'POST', body: JSON.stringify(form) });
      onReady(payload.user);
    } catch (err) {
      setError((err as Error).message);
    }
  }

  return (
    <AuthCard title="Primeiro acesso" subtitle="Crie seu usuario principal para proteger o painel.">
      <form onSubmit={submit} className="stack">
        <Field label="Nome" value={form.name} onChange={(name) => setForm({ ...form, name })} />
        <Field label="Email" type="email" value={form.email} onChange={(email) => setForm({ ...form, email })} />
        <Field label="Senha" type="password" value={form.password} onChange={(password) => setForm({ ...form, password })} />
        {error && <p className="error">{error}</p>}
        <button className="primary">Criar acesso</button>
      </form>
    </AuthCard>
  );
}

function LoginScreen({ onLogin }: { onLogin: (user: User) => void }) {
  const [form, setForm] = useState({ email: '', password: '' });
  const [error, setError] = useState('');

  async function submit(event: FormEvent) {
    event.preventDefault();
    setError('');
    try {
      const payload = await api<{ user: User }>('auth/login', { method: 'POST', body: JSON.stringify(form) });
      onLogin(payload.user);
    } catch (err) {
      setError((err as Error).message);
    }
  }

  return (
    <AuthCard title="Entrar" subtitle="Acesse seu painel pessoal de continuidade.">
      <form onSubmit={submit} className="stack">
        <Field label="Email" type="email" value={form.email} onChange={(email) => setForm({ ...form, email })} />
        <Field label="Senha" type="password" value={form.password} onChange={(password) => setForm({ ...form, password })} />
        {error && <p className="error">{error}</p>}
        <button className="primary">Entrar</button>
      </form>
    </AuthCard>
  );
}

function AuthCard({ title, subtitle, children }: { title: string; subtitle: string; children: React.ReactNode }) {
  return (
    <main className="auth-shell">
      <section className="auth-card">
        <div className="brand-mark">PC</div>
        <h1>{title}</h1>
        <p>{subtitle}</p>
        {children}
      </section>
    </main>
  );
}

function Workspace({ user, onLogout }: { user: User; onLogout: () => void }) {
  const [view, setView] = useState('hoje');
  const [dashboard, setDashboard] = useState<Dashboard | null>(null);
  const [projects, setProjects] = useState<Project[]>([]);
  const [tasks, setTasks] = useState<Task[]>([]);
  const [studyPlans, setStudyPlans] = useState<StudyPlan[]>([]);
  const [settings, setSettings] = useState<Settings | null>(null);
  const [review, setReview] = useState<Review | null>(null);
  const [notice, setNotice] = useState('');
  const [loadErrors, setLoadErrors] = useState<LoadErrors>({});

  async function loadOne(key: keyof LoadErrors, loader: () => Promise<void>) {
    try {
      await loader();
      setLoadErrors((current) => ({ ...current, [key]: undefined }));
    } catch (err) {
      setLoadErrors((current) => ({ ...current, [key]: (err as Error).message }));
    }
  }

  const loaders = useMemo(() => ({
    dashboard: () => api<{ dashboard: Dashboard }>('dashboard').then((r) => setDashboard(r.dashboard)),
    projects: () => api<{ projects: Project[] }>('projects').then((r) => setProjects(r.projects)),
    tasks: () => api<{ tasks: Task[] }>('tasks').then((r) => setTasks(r.tasks)),
    study: () => api<{ studyPlans: StudyPlan[] }>('study-plans').then((r) => setStudyPlans(r.studyPlans)),
    settings: () => api<{ settings: Settings }>('settings').then((r) => setSettings(r.settings)),
    review: () => api<{ review: Review }>('review/weekly').then((r) => setReview(r.review)),
  }), []);

  async function refreshAll() {
    await Promise.all([
      loadOne('dashboard', loaders.dashboard),
      loadOne('projects', loaders.projects),
      loadOne('tasks', loaders.tasks),
      loadOne('study', loaders.study),
    ]);
  }

  useEffect(() => {
    refreshAll();
    loadOne('settings', loaders.settings);
  }, []);

  useEffect(() => {
    if (view === 'tarefas') loadOne('tasks', loaders.tasks);
    if (view === 'estudos') loadOne('study', loaders.study);
    if (view === 'projetos') loadOne('projects', loaders.projects);
    if (view === 'revisao') loadOne('review', loaders.review);
    if (view === 'config') loadOne('settings', loaders.settings);
  }, [view]);

  async function logout() {
    await api('auth/logout', { method: 'POST' });
    onLogout();
  }

  const nav = [
    ['hoje', 'Hoje'],
    ['projetos', 'Projetos'],
    ['tarefas', 'Tarefas'],
    ['estudos', 'Estudos'],
    ['revisao', 'Revisao'],
    ['config', 'Config'],
  ];

  return (
    <main className="app-shell">
      <aside className="sidebar">
        <div>
          <div className="app-title">
            <span className="brand-mark small">PC</span>
            <strong>Continuidade</strong>
          </div>
          <nav>
            {nav.map(([id, label]) => (
              <button key={id} className={view === id ? 'active' : ''} onClick={() => setView(id)}>
                {label}
              </button>
            ))}
          </nav>
        </div>
        <div className="user-box">
          <span>{user.name}</span>
          <button onClick={logout}>Sair</button>
        </div>
      </aside>

      <section className="content">
        {notice && <button className="notice" onClick={() => setNotice('')}>{notice}</button>}
        {view === 'hoje' && <DashboardView dashboard={dashboard} error={loadErrors.dashboard} onRefresh={refreshAll} />}
        {view === 'projetos' && <ProjectsView projects={projects} error={loadErrors.projects} reload={refreshAll} notify={setNotice} />}
        {view === 'tarefas' && <TasksView tasks={tasks} projects={projects} error={loadErrors.tasks} reload={refreshAll} notify={setNotice} />}
        {view === 'estudos' && <StudyView studyPlans={studyPlans} error={loadErrors.study} reload={refreshAll} notify={setNotice} />}
        {view === 'revisao' && <ReviewView review={review} error={loadErrors.review} />}
        {view === 'config' && settings && <SettingsView settings={settings} error={loadErrors.settings} reload={() => loadOne('settings', loaders.settings)} notify={setNotice} />}
      </section>
    </main>
  );
}

function DashboardView({ dashboard, error, onRefresh }: { dashboard: Dashboard | null; error?: string; onRefresh: () => void }) {
  if (error) return <Panel title="Hoje"><ErrorMessage message={error} /></Panel>;
  if (!dashboard) return <Panel title="Hoje"><p>Carregando...</p></Panel>;
  return (
    <div className="page-grid">
      <Header title="Hoje" action={<button onClick={onRefresh}>Atualizar</button>} />
      <div className="metrics">
        <Metric label="Projetos" value={dashboard.counts.projects} />
        <Metric label="Tarefas" value={dashboard.counts.tasks} />
        <Metric label="Estudos" value={dashboard.counts.study_plans} />
      </div>
      <Panel title="Foco de agora">
        <ItemList items={dashboard.focusTasks} empty="Nenhuma tarefa pedindo atencao." render={(task) => (
          <Item title={task.title} meta={`${formatDate(task.due_at)}${task.project_title ? ` - ${task.project_title}` : ''}`} tone={task.importance} />
        )} />
      </Panel>
      <Panel title="Projetos parados">
        <ItemList items={dashboard.staleProjects} empty="Nenhum projeto estacionado." render={(project) => (
          <Item title={project.title} meta={project.next_action || 'Definir proxima acao'} tone="alta" />
        )} />
      </Panel>
      <Panel title="Estudo">
        <ItemList items={dashboard.studyQueue} empty="Nenhum estudo marcado para agora." render={(plan) => (
          <Item title={plan.title} meta={`${plan.progress}% - ${formatDate(plan.next_session_at)}`} tone="media" />
        )} />
      </Panel>
    </div>
  );
}

function ProjectsView({ projects, error, reload, notify }: { projects: Project[]; error?: string; reload: () => void; notify: (text: string) => void }) {
  const [form, setForm] = useState(emptyProject);

  async function submit(event: FormEvent) {
    event.preventDefault();
    await api('projects', { method: 'POST', body: JSON.stringify(form) });
    setForm(emptyProject);
    notify('Projeto criado.');
    reload();
  }

  async function update(project: Project, patch: Partial<Project>) {
    await api(`projects/${project.id}`, { method: 'PUT', body: JSON.stringify({ ...project, ...patch }) });
    reload();
  }

  return (
    <div className="page-grid">
      <Header title="Projetos" />
      {error && <ErrorMessage message={error} />}
      <Panel title="Novo projeto">
        <form onSubmit={submit} className="form-grid">
          <Field label="Nome" value={form.title} onChange={(title) => setForm({ ...form, title })} />
          <Field label="Proxima acao" value={form.next_action} onChange={(next_action) => setForm({ ...form, next_action })} />
          <Select label="Status" value={form.status} onChange={(status) => setForm({ ...form, status })} options={['ideia', 'ativo', 'pausado', 'concluido', 'abandonado']} />
          <Select label="Prioridade" value={form.priority} onChange={(priority) => setForm({ ...form, priority })} options={['baixa', 'media', 'alta']} />
          <Field label="Estagnar apos dias" type="number" value={String(form.stale_after_days)} onChange={(value) => setForm({ ...form, stale_after_days: Number(value) })} />
          <Textarea label="Notas" value={form.notes} onChange={(notes) => setForm({ ...form, notes })} />
          <button className="primary">Adicionar</button>
        </form>
      </Panel>
      <div className="cards">
        {projects.map((project) => (
          <article className="item-card" key={project.id}>
            <div>
              <strong>{project.title}</strong>
              <p>{project.next_action || 'Sem proxima acao definida.'}</p>
            </div>
            <div className="row">
              <Badge tone={project.priority}>{project.priority}</Badge>
              <select value={project.status} onChange={(event) => update(project, { status: event.target.value as Project['status'] })}>
                {['ideia', 'ativo', 'pausado', 'concluido', 'abandonado'].map((status) => <option key={status}>{status}</option>)}
              </select>
            </div>
            <div className="row">
              <button onClick={() => api(`projects/${project.id}/touch`, { method: 'POST' }).then(reload)}>Marcar avanco</button>
              <button className="ghost danger" onClick={() => api(`projects/${project.id}`, { method: 'DELETE' }).then(reload)}>Apagar</button>
            </div>
          </article>
        ))}
      </div>
    </div>
  );
}

function TasksView({ tasks, projects, error, reload, notify }: { tasks: Task[]; projects: Project[]; error?: string; reload: () => void; notify: (text: string) => void }) {
  const [form, setForm] = useState(emptyTask);

  async function submit(event: FormEvent) {
    event.preventDefault();
    await api('tasks', {
      method: 'POST',
      body: JSON.stringify({
        ...form,
        project_id: form.project_id ? Number(form.project_id) : null,
        due_at: normalizeDateTime(form.due_at),
      }),
    });
    setForm(emptyTask);
    notify('Tarefa criada.');
    reload();
  }

  return (
    <div className="page-grid">
      <Header title="Tarefas e lembretes" />
      {error && <ErrorMessage message={error} />}
      <Panel title="Nova tarefa">
        <form onSubmit={submit} className="form-grid">
          <Field label="Titulo" value={form.title} onChange={(title) => setForm({ ...form, title })} />
          <label>
            Projeto
            <select value={form.project_id} onChange={(event) => setForm({ ...form, project_id: event.target.value })}>
              <option value="">Sem projeto</option>
              {projects.map((project) => <option key={project.id} value={project.id}>{project.title}</option>)}
            </select>
          </label>
          <Field label="Quando" type="datetime-local" value={form.due_at} onChange={(due_at) => setForm({ ...form, due_at })} />
          <Select label="Importancia" value={form.importance} onChange={(importance) => setForm({ ...form, importance })} options={['baixa', 'media', 'alta']} />
          <Select label="Recorrencia" value={form.recurrence_rule} onChange={(recurrence_rule) => setForm({ ...form, recurrence_rule })} options={['nenhuma', 'diaria', 'semanal', 'mensal']} />
          <label className="check"><input type="checkbox" checked={form.email_reminder} onChange={(event) => setForm({ ...form, email_reminder: event.target.checked })} /> Avisar por email</label>
          <button className="primary">Adicionar</button>
        </form>
      </Panel>
      <div className="list">
        {tasks.map((task) => (
          <article className={`list-row ${task.completed_at ? 'done' : ''}`} key={task.id}>
            <div>
              <strong>{task.title}</strong>
              <p>{formatDate(task.due_at)} {task.project_title ? `- ${task.project_title}` : ''}</p>
            </div>
            <div className="row">
              <Badge tone={task.importance}>{task.importance}</Badge>
              <button onClick={() => api(`tasks/${task.id}/complete`, { method: 'POST' }).then(reload)}>{task.completed_at ? 'Reabrir' : 'Concluir'}</button>
              <button className="ghost danger" onClick={() => api(`tasks/${task.id}`, { method: 'DELETE' }).then(reload)}>Apagar</button>
            </div>
          </article>
        ))}
      </div>
    </div>
  );
}

function StudyView({ studyPlans, error, reload, notify }: { studyPlans: StudyPlan[]; error?: string; reload: () => void; notify: (text: string) => void }) {
  const [form, setForm] = useState(emptyStudy);

  async function submit(event: FormEvent) {
    event.preventDefault();
    await api('study-plans', { method: 'POST', body: JSON.stringify({ ...form, next_session_at: normalizeDateTime(form.next_session_at) }) });
    setForm(emptyStudy);
    notify('Plano de estudo criado.');
    reload();
  }

  async function update(plan: StudyPlan, progress: number) {
    await api(`study-plans/${plan.id}`, { method: 'PUT', body: JSON.stringify({ ...plan, progress }) });
    reload();
  }

  return (
    <div className="page-grid">
      <Header title="Plano de estudos" />
      {error && <ErrorMessage message={error} />}
      <Panel title="Novo estudo">
        <form onSubmit={submit} className="form-grid">
          <Field label="Tema" value={form.title} onChange={(title) => setForm({ ...form, title })} />
          <Field label="Minutos por semana" type="number" value={String(form.weekly_minutes)} onChange={(weekly_minutes) => setForm({ ...form, weekly_minutes: Number(weekly_minutes) })} />
          <Field label="Proxima sessao" type="datetime-local" value={form.next_session_at} onChange={(next_session_at) => setForm({ ...form, next_session_at })} />
          <Textarea label="Objetivo" value={form.objective} onChange={(objective) => setForm({ ...form, objective })} />
          <Textarea label="Materiais" value={form.materials} onChange={(materials) => setForm({ ...form, materials })} />
          <button className="primary">Adicionar</button>
        </form>
      </Panel>
      <div className="cards">
        {studyPlans.map((plan) => (
          <article className="item-card" key={plan.id}>
            <div>
              <strong>{plan.title}</strong>
              <p>{plan.objective || 'Sem objetivo descrito.'}</p>
            </div>
            <label>
              Progresso: {plan.progress}%
              <input type="range" min="0" max="100" value={plan.progress} onChange={(event) => update(plan, Number(event.target.value))} />
            </label>
            <div className="row">
              <span>{formatDate(plan.next_session_at)}</span>
              <button className="ghost danger" onClick={() => api(`study-plans/${plan.id}`, { method: 'DELETE' }).then(reload)}>Apagar</button>
            </div>
          </article>
        ))}
      </div>
    </div>
  );
}

function ReviewView({ review, error }: { review: Review | null; error?: string }) {
  if (error) return <Panel title="Revisao semanal"><ErrorMessage message={error} /></Panel>;
  if (!review) return <Panel title="Revisao semanal"><p>Carregando...</p></Panel>;
  return (
    <div className="page-grid">
      <Header title="Revisao semanal" />
      <Panel title="Projetos novos"><ItemList items={review.newProjects} empty="Nenhum projeto novo nesta semana." render={(p) => <Item title={p.title} meta={p.status} tone={p.priority} />} /></Panel>
      <Panel title="Tarefas concluidas"><ItemList items={review.completedTasks} empty="Nenhuma tarefa concluida nesta semana." render={(t) => <Item title={t.title} meta={formatDate(t.completed_at)} tone={t.importance} />} /></Panel>
      <Panel title="Atrasos"><ItemList items={review.overdueTasks} empty="Sem atrasos." render={(t) => <Item title={t.title} meta={formatDate(t.due_at)} tone="alta" />} /></Panel>
      <Panel title="Projetos pedindo decisao"><ItemList items={review.staleProjects} empty="Nada parado alem do limite." render={(p) => <Item title={p.title} meta={p.next_action || 'Definir proxima acao'} tone="alta" />} /></Panel>
    </div>
  );
}

function SettingsView({ settings, error, reload, notify }: { settings: Settings; error?: string; reload: () => void; notify: (text: string) => void }) {
  const [form, setForm] = useState({
    email_to: settings.email_to,
    alerts_enabled: Boolean(Number(settings.alerts_enabled)),
    digest_hour: settings.digest_hour,
    timezone: settings.timezone,
  });

  async function submit(event: FormEvent) {
    event.preventDefault();
    await api('settings', { method: 'PUT', body: JSON.stringify(form) });
    notify('Configuracoes salvas.');
    reload();
  }

  return (
    <div className="page-grid">
      <Header title="Configuracoes" />
      {error && <ErrorMessage message={error} />}
      <Panel title="Alertas por email">
        <form onSubmit={submit} className="form-grid">
          <Field label="Email para alertas" type="email" value={form.email_to} onChange={(email_to) => setForm({ ...form, email_to })} />
          <Field label="Hora do resumo" type="number" value={String(form.digest_hour)} onChange={(digest_hour) => setForm({ ...form, digest_hour: Number(digest_hour) })} />
          <Field label="Fuso horario" value={form.timezone} onChange={(timezone) => setForm({ ...form, timezone })} />
          <label className="check"><input type="checkbox" checked={form.alerts_enabled} onChange={(event) => setForm({ ...form, alerts_enabled: event.target.checked })} /> Alertas ativos</label>
          <button className="primary">Salvar</button>
        </form>
      </Panel>
    </div>
  );
}

function Header({ title, action }: { title: string; action?: React.ReactNode }) {
  return <header className="page-header"><h1>{title}</h1>{action}</header>;
}

function Panel({ title, children }: { title: string; children: React.ReactNode }) {
  return <section className="panel"><h2>{title}</h2>{children}</section>;
}

function ErrorMessage({ message }: { message: string }) {
  return (
    <div className="error-box">
      <strong>Algo falhou ao carregar esta area.</strong>
      <p>{message}</p>
    </div>
  );
}

function Metric({ label, value }: { label: string; value: number }) {
  return <div className="metric"><span>{label}</span><strong>{value}</strong></div>;
}

function Item({ title, meta, tone }: { title: string; meta: string; tone: string }) {
  return <div className="compact-item"><Badge tone={tone}>{tone}</Badge><div><strong>{title}</strong><p>{meta}</p></div></div>;
}

function ItemList<T>({ items, empty, render }: { items: T[]; empty: string; render: (item: T) => React.ReactNode }) {
  if (!items.length) return <p className="empty">{empty}</p>;
  return <div className="list compact">{items.map((item, index) => <React.Fragment key={index}>{render(item)}</React.Fragment>)}</div>;
}

function Badge({ tone, children }: { tone: string; children: React.ReactNode }) {
  return <span className={`badge ${tone}`}>{children}</span>;
}

function Field({ label, value, onChange, type = 'text' }: { label: string; value: string; onChange: (value: string) => void; type?: string }) {
  return <label>{label}<input type={type} value={value} onChange={(event) => onChange(event.target.value)} /></label>;
}

function Textarea({ label, value, onChange }: { label: string; value: string; onChange: (value: string) => void }) {
  return <label className="wide">{label}<textarea value={value} onChange={(event) => onChange(event.target.value)} /></label>;
}

function Select({ label, value, onChange, options }: { label: string; value: string; onChange: (value: string) => void; options: string[] }) {
  return <label>{label}<select value={value} onChange={(event) => onChange(event.target.value)}>{options.map((option) => <option key={option}>{option}</option>)}</select></label>;
}

createRoot(document.getElementById('root')!).render(<App />);

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register(new URL(`${appBasePath()}sw.js`, window.location.origin)).catch(() => undefined);
  });
}
