import Navbar from '@/components/Navbar';
import Footer from '@/components/Footer';
import DocsLayout from '@/components/docs/DocsLayout';

export const metadata = {
  title: 'Install Mealie — DashCaddy Docs',
  description: 'Install and configure Mealie via DashCaddy. Recipe manager and meal planner with grocery lists',
};

export default function mealieDocsPage() {
  return (
    <div className="flex min-h-screen flex-col bg-surface-950 text-surface-50">
      <Navbar />
      <DocsLayout
        title="Install Mealie"
        intro="Recipe manager and meal planner with grocery lists"
      >
<div className="mb-6 flex flex-wrap gap-3 text-xs font-semibold">
  <span className="rounded-full bg-surface-800 px-3 py-1 text-surface-300">Category: Productivity</span>
  <span className="rounded-full px-3 py-1" style={{ backgroundColor: '#7cf2c022', color: '#7cf2c0' }}>Difficulty: Easy</span>
  <span className="rounded-full bg-surface-800 px-3 py-1 text-surface-300">Docker image: <code className="text-brand-400">ghcr.io/mealie-recipes/mealie:latest</code></span>
</div>

<h2>What is Mealie?</h2>
<p>Recipe manager and meal planner with grocery lists</p>
<p>Mealie ships as a self-contained Docker image that DashCaddy provisions with one click. DashCaddy handles the container lifecycle, DNS record, Caddy reverse-proxy entry, and HTTPS certificate so you can focus on using Mealie, not installing it.</p>

<h2>Prerequisites</h2>
<ul>
  <li>A running DashCaddy host with the dashboard accessible (default URL: <code>https://status.sami</code>; configurable via the <code>dashboardHost</code> setting in <code>config.json</code>).</li>
  <li>You must be signed in to the dashboard with an admin session, or have an API key with admin scope (<code>POST /api/v1/auth/keys</code> to create one).</li>
  <li>No special host paths required.</li>
  <li>For HTTPS with a real certificate, Technitium DNS must be configured and the host must have port 80/443 reachable from the internet. Otherwise DashCaddy will fall back to direct-IP access or a self-signed certificate.</li>
</ul>

<h2>Install via the DashCaddy dashboard</h2>
<ol>
  <li>Sign in at <code>https://status.sami</code> (or your host's dashboard URL).</li>
  <li>Click the <strong>📱 App Selector</strong> button on the dashboard home page.</li>
  <li>Pick <strong>Mealie</strong> from the Productivity category.</li>
  <li>Fill in the deployment form: subdomain (default suggestion: <code>mealie</code>), host port (default: <code>9925</code>).</li>
  <li>Click <strong>Deploy</strong>. DashCaddy will pull the image, create persistent volumes, write a Caddy route, create the DNS record, and wait up to 30 seconds for the container's health check (<code>/</code>) to pass.</li>
  <li>When the dashboard shows the service as <strong>Running</strong>, the URL (built from your subdomain and configured TLD) is clickable. The deploy API returns a synchronous response with <code>&#123;success, containerId, url, message, setupInstructions&#125;</code> — there is no separate status-poll endpoint; the dashboard updates live.</li>
</ol>

<h2>Install via the REST API</h2>
<p>Authenticate with an API key (or a JWT minted via <code>POST /api/v1/auth/jwt</code>). Send as <code>X-API-Key: dk_...</code> or <code>Authorization: Bearer &lt;jwt&gt;</code>.</p>
<pre className="overflow-x-auto rounded-lg bg-surface-900 p-4 text-sm"><code>curl -X POST https://status.sami/api/v1/apps/deploy \\
  -H "X-API-Key: dk_your_api_key" \\
  -H "Content-Type: application/json" \\
  -d '&#123;
    "appId": "mealie",
    "config": &#123;
      "subdomain": "mealie",
      "port": 9925
    &#125;
  &#125;'</code></pre>
<p>The full body schema is in <code>src/utilities/validate.js</code> (Joi schema <code>appDeploy</code>). All <code>config.*</code> fields except <code>subdomain</code> are optional. Notable options:</p>
<ul>
  <li><code>config.port</code> — host port (1–65535). Defaults to the template's <code>defaultPort</code>.</li>
  <li><code>config.mediaPath</code> — host directory to mount as the media library.</li>
  <li><code>config.plexClaimToken</code> — Plex claim token (when the upstream service needs one).</li>
  <li><code>config.useExisting: true</code> + <code>existingContainerId</code> — attach DashCaddy metadata to an already-running container instead of pulling a new image.</li>
  <li><code>config.tailscaleOnly: true</code> — restrict the reverse-proxy entry to your Tailscale network.</li>
  <li><code>config.allowedIPs</code> — array of CIDR ranges allowed past the reverse proxy.</li>
  <li><code>config.createDns: false</code> — skip DNS record creation (use when the subdomain already resolves).</li>
  <li><code>config.resources</code> — <code>&#123;memory, cpus&#125;</code> limits applied to the container.</li>
</ul>

<h2>Install via the AI Intent Router (returns a structured intent)</h2>
<p>The Intent Router returns a structured intent, not a deployed container. To deploy via AI, send natural language to:</p>
<pre className="overflow-x-auto rounded-lg bg-surface-900 p-4 text-sm"><code>curl -X POST https://status.sami/api/v1/ai/intent \\
  -H "X-API-Key: dk_your_api_key" \\
  -H "Content-Type: application/json" \\
  -d '&#123; "message": "Deploy Mealie on my home host and expose it at mealie.sami" &#125;'</code></pre>
<p>The response includes <code>intent</code>, <code>action</code>, <code>parameters</code>, and <code>followup</code> — your client (or the MCP server) must then call <code>POST /api/v1/apps/deploy</code> with those parameters to actually provision the container.</p>

<h2>Install via the MCP Server</h2>
<p>For AI agents (Claude Desktop, Hermes, etc.) configure the MCP server (<code>src/mcp/mcp-server.js</code>) with:</p>
<pre className="overflow-x-auto rounded-lg bg-surface-900 p-4 text-sm"><code>DASHCADDY_URL=https://status.sami:3001  # internal API URL, may differ from dashboard URL
DASHCADDY_API_KEY=dk_your_api_key</code></pre>
<p>The server exposes <code>dashcaddy_deploy_app</code>. Note: this tool writes the Caddy route and creates the <code>services.json</code> entry, but it does NOT pull the Docker image or start the container. You must run <code>docker pull ghcr.io/mealie-recipes/mealie:latest</code> and start the container yourself for the URL to actually serve traffic. For a fully-managed deployment, call <code>POST /api/v1/apps/deploy</code> directly from your agent.</p>

<h2>Post-install: first-run checklist</h2>
<ol>
  <li>Default login: changeme@example.com / MyPassword</li>
  <li>Import recipes from URLs or add them manually</li>
  <li>Create meal plans and generate shopping lists</li>
</ol>
<h2>Volumes and persistent data</h2>
<p>DashCaddy creates these volume mounts in the container spec:</p>
<ul>
<li><code>/opt/mealie/data:/app/data</code></li>
</ul>
<p>All paths are host paths (left side) mapped into the container (right side). Restarting the container preserves data; reinstalling the template preserves it unless you explicitly pass <code>config.useExisting: false</code> AND wipe the volume. Bind mounts use the host-path conventions above (e.g. <code>/opt/plex/config</code> becomes a bind mount to the host directory of the same path).</p>

<h2>Environment variables</h2>
<ul>
  <li><code>ALLOW_SIGNUP</code></li>
  <li><code>MAX_WORKERS</code></li>
  <li><code>WEB_CONCURRENCY</code></li>
  <li><code>BASE_URL</code></li>
</ul><p>These are baked into the template at deploy time and shipped to the container. The deploy handler does NOT allow overriding them via the API payload — to change them you must edit the template definition in <code>dashcaddy-api/src/docker/app-templates.js</code>.</p>

<h2>Updating the image</h2>
<p>There is no built-in auto-update — DashCaddy does NOT poll for new image digests. To pull a new version:</p>
<ol>
  <li>SSH into the DashCaddy host and run <code>docker pull ghcr.io/mealie-recipes/mealie:latest</code>.</li>
  <li>Restart the container: <code>docker restart &lt;containerId&gt;</code> (find the ID via <code>GET /api/v1/services</code> or the dashboard).</li>
  <li>Or deploy Watchtower from this catalog (separate template that polls Docker Hub and updates other containers automatically, default schedule <code>0 0 4 * * *</code> = 04:00 daily).</li>
</ol>

<h2>Backups</h2>
<p>The default backup policy includes the entire <code>/app/data/</code> directory (services, config, credentials, stats) AND all Docker volumes. Backups are scheduled via <code>backup-config.json</code> — the default schedule is configurable, not "nightly" out of the box. To restore on a fresh host, redeploy the same template and then call <code>POST /api/v1/apps/&#123;appId&#125;/restore</code> with a backup ID from <code>GET /api/v1/backups/history</code>.</p>

<h2>Troubleshooting</h2>
<p>Common issues with Mealie:</p>
<ul>
  <li><strong>Container won't start:</strong> check the dashboard's Logs panel. Most startup failures are permission errors on the host-path volume.</li>
  <li><strong>URL not reachable after deploy:</strong> the Caddy route was written but DNS hasn't propagated, or port 80/443 is firewalled. Check <code>GET /api/v1/dns/records</code> and <code>systemctl status caddy</code> on the host.</li>
  <li><strong>Health check timeout (deploy returns 30s after start):</strong> the container is starting but <code>/</code> is not returning 200. Inspect <code>docker logs &lt;containerId&gt;</code> directly.</li>
</ul>
<p>For layer-by-layer diagnostics, see the <a href="/docs/troubleshooting" className="text-brand-400 underline">Troubleshooting guide</a>.</p>

<hr className="my-8 border-surface-700" />
<p className="text-sm text-surface-400">
Template ID: <code>mealie</code>. Source: <code>dashcaddy-api/src/docker/app-templates.js</code>.
</p>
      </DocsLayout>
      <Footer />
    </div>
  );
}
