#!/bin/bash
# Exit immediately on error, treat unset variables as errors, propagate pipe failures.
set -euo pipefail
# Load shared log/warn/skip helpers from the installer library.
source "$(dirname "${BASH_SOURCE[0]}")/../../lib/logging.sh"

log "Installing mail stack (isync, msmtp, notmuch, alot, w3m)..."
# isync/mbsync: IMAP sync daemon; msmtp: SMTP sender; notmuch: fast mail indexer;
# alot: terminal mail UI built on notmuch; w3m: renders HTML mail parts as plain text.
sudo pacman -S --noconfirm --needed isync msmtp notmuch alot w3m

# In unattended installs (answerfile mode / no TTY) there is no operator to answer
# the account prompts below, so install the tools and stop cleanly here; the user
# configures their mail account after first boot.
if [[ "${MARCHY_UNATTENDED:-0}" == "1" || ! -t 0 ]]; then
    skip "Unattended mode — mail stack installed; configure accounts after first boot."
    exit 0
fi

# ── Credentials ───────────────────────────────────────────────────────────────
# Collect all account details interactively before writing any config files,
# so the user can review/abort cleanly before any files are touched.
read -rp  "Full name                          : " FULL_NAME
read -rp  "Email address                      : " EMAIL
read -rp  "IMAP host (e.g. mail.example.com)  : " IMAP_HOST
# Default IMAP port to 993 (IMAPS/TLS); user may override for non-standard setups.
read -rp  "IMAP port [993]                    : " IMAP_PORT;  IMAP_PORT="${IMAP_PORT:-993}"
# Default IMAP username to the email address, which most providers require.
read -rp  "IMAP username [$EMAIL]             : " IMAP_USER;  IMAP_USER="${IMAP_USER:-$EMAIL}"
# -s suppresses echo so the password is not visible; trailing `echo` restores the newline.
read -rsp "IMAP password                      : " IMAP_PASS;  echo
read -rp  "SMTP host (e.g. mail.example.com)  : " SMTP_HOST
# Default SMTP port to 587 (STARTTLS submission); use 465 for implicit TLS.
read -rp  "SMTP port [587]                    : " SMTP_PORT;  SMTP_PORT="${SMTP_PORT:-587}"

# Root of the local Maildir tree; mbsync creates per-folder subdirectories here.
MAILDIR="$HOME/Mail"
mkdir -p "$MAILDIR"

# ── mbsync ────────────────────────────────────────────────────────────────────
log "Writing ~/.mbsyncrc..."
# Heredoc writes the full mbsync config in one shot using the variables collected
# above.  Overwriting on each run means re-running the script updates credentials.
cat > ~/.mbsyncrc << EOF
IMAPAccount main
Host     $IMAP_HOST
Port     $IMAP_PORT
User     $IMAP_USER
Pass     $IMAP_PASS
SSLType  IMAPS
# Trust the system CA bundle rather than pinning a specific server certificate.
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore main-remote
Account main

MaildirStore main-local
# SubFolders Verbatim: mirror the IMAP folder hierarchy exactly as subdirectories.
SubFolders Verbatim
Path      $MAILDIR/
Inbox     $MAILDIR/INBOX

Channel main
Far  :main-remote:
Near :main-local:
# Sync all IMAP folders; replace * with a list to restrict to specific folders.
Patterns *
# Create Both: automatically create missing folders on either side.
Create   Both
# SyncState *: store .mbsyncstate alongside each Maildir folder for portability.
SyncState *
# Expunge Both: propagate deletions bidirectionally so remote deletes appear locally.
Expunge  Both
EOF
# 600 permissions keep the plaintext password private from other local users.
chmod 600 ~/.mbsyncrc

# ── msmtp ─────────────────────────────────────────────────────────────────────
log "Writing ~/.msmtprc..."
# msmtp acts as a drop-in sendmail replacement; alot invokes it via the
# sendmail_command field in the alot account block written further below.
cat > ~/.msmtprc << EOF
defaults
tls            on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
# Log every sent message with a timestamp to aid debugging delivery failures.
logfile        ~/.msmtp.log

account        main
host           $SMTP_HOST
port           $SMTP_PORT
auth           on
user           $IMAP_USER
password       $IMAP_PASS
from           $EMAIL

# Make "main" the account used when msmtp is called without an explicit -a flag.
account default : main
EOF
# Same 600 restriction as mbsyncrc — this file contains a plaintext SMTP password.
chmod 600 ~/.msmtprc

# ── notmuch ───────────────────────────────────────────────────────────────────
log "Configuring notmuch..."
# notmuch config set writes to ~/.notmuch-config; each call is idempotent
# (overwrites the existing key) so re-running the script is safe.
notmuch config set user.name           "$FULL_NAME"
notmuch config set user.email          "$EMAIL"
# Point notmuch at the Maildir root so `notmuch new` scans the right location.
notmuch config set database.path       "$MAILDIR"
# Synchronise notmuch tags with Maildir flags (Seen, Replied, etc.) bidirectionally.
notmuch config set maildir.synchronize_flags true
# Tag every newly indexed message as unread and inbox by default.
notmuch config set new.tags            "unread;inbox"

# post-new hook: tag sent mail, remove inbox from trash
# notmuch executes this script automatically after `notmuch new` indexes messages.
mkdir -p "$MAILDIR/.notmuch/hooks"
cat > "$MAILDIR/.notmuch/hooks/post-new" << 'EOF'
#!/bin/bash
# Apply folder-based tags and strip inbox/unread from non-inbox folders.
notmuch tag +sent    -inbox -- folder:Sent
notmuch tag +trash   -inbox -unread -- folder:Trash
notmuch tag +draft   -inbox -- folder:Drafts
notmuch tag +spam    -inbox -unread -- folder:Spam folder:Junk
EOF
# The hook must be executable or notmuch will silently skip it.
chmod +x "$MAILDIR/.notmuch/hooks/post-new"

# ── alot ──────────────────────────────────────────────────────────────────────
# The bindings section lives in ~/Dotfiles/alot/config (symlinked by shell-setup.sh).
# Write only the account block, which contains machine-specific paths/identity.
log "Writing account details into ~/Dotfiles/alot/config..."
ALOT_CFG="$HOME/Dotfiles/alot/config"
# Use an inline Python script to splice the [accounts] block into the existing
# config file.  sed struggles with multi-line replacements; Python's re.sub with
# re.DOTALL handles the entire block atomically and overwrites any prior values.
# Replace the [[main]] account block in-place (sed removes old block, cat appends new one)
python3 - "$ALOT_CFG" "$FULL_NAME" "$EMAIL" "$MAILDIR" << 'PYEOF'
import sys, re
path, name, email, maildir = sys.argv[1:]
block = f"""[accounts]
    [[main]]
        realname        = {name}
        address         = {email}
        sendmail_command = msmtp -a main
        sent_box        = maildir://{maildir}/Sent
        draft_box       = maildir://{maildir}/Drafts
"""
with open(path) as f:
    text = f.read()
# Replace from [accounts] up to the next top-level section or end-of-file,
# ensuring any previous account block is cleanly overwritten on re-runs.
text = re.sub(r'\[accounts\].*?(?=\n\[|\Z)', block, text, flags=re.DOTALL)
with open(path, 'w') as f:
    f.write(text)
PYEOF

# ── mailcap (HTML email rendering via w3m) ────────────────────────────────────
log "Writing ~/.mailcap..."
# grep -qxF checks for an exact full-line match to avoid appending duplicates
# on repeated runs; the || only appends the entry when it is absent.
# w3m -dump converts HTML to plain text; copiousoutput tells mail clients
# to page the result rather than try to display it inline.
grep -qxF "text/html; w3m -dump -o document_charset=%{charset} '%s'; nametemplate=%s.html; copiousoutput" ~/.mailcap 2>/dev/null \
    || echo "text/html; w3m -dump -o document_charset=%{charset} '%s'; nametemplate=%s.html; copiousoutput" >> ~/.mailcap

# ── systemd timer for periodic sync ───────────────────────────────────────────
# This whole block is best-effort: when the installer runs from a bare TTY or a
# chroot there is no per-user systemd session bus (and ~/.config may not yet be
# owned by the invoking user), so `systemctl --user` and even the mkdir can fail.
# None of that should abort the module — the mail config is already in place and
# the timer can be (re)created on first graphical/login session. We therefore
# warn and continue instead of letting `set -e` kill the install.
log "Installing mbsync systemd user timer (every 5 min)..."
# User units live under ~/.config/systemd/user/; --user scope requires no root
# and units only run while the user session is active.
if mkdir -p ~/.config/systemd/user 2>/dev/null; then
    # Type=oneshot: systemd marks the service done as soon as ExecStart exits,
    # appropriate for a batch sync command that runs and terminates.
    # After=network-online.target: prevents sync attempts before a route is available.
    cat > ~/.config/systemd/user/mbsync.service << EOF
[Unit]
Description=Sync mail with mbsync
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/mbsync -a
# Re-index immediately after each sync so alot reflects new messages right away.
ExecStartPost=/usr/bin/notmuch new
EOF

    # OnBootSec=2min: delay the first run by 2 min to avoid startup congestion.
    # OnUnitActiveSec=5min: repeat 5 min after the previous run finishes.
    cat > ~/.config/systemd/user/mbsync.timer << EOF
[Unit]
Description=Run mbsync every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=mbsync.service

[Install]
WantedBy=timers.target
EOF

    # Reload the user manager so it picks up the newly written unit files.
    # A successful daemon-reload means a user session bus is available; only then
    # is it worth trying to enable/start the timer. Guard both so the absence of
    # a session during install is reported, not fatal.
    if systemctl --user daemon-reload 2>/dev/null; then
        # enable makes the timer survive reboots; --now also starts it now.
        systemctl --user enable --now mbsync.timer 2>/dev/null \
            || warn "Could not enable mbsync.timer now — run: systemctl --user enable --now mbsync.timer"
    else
        warn "No user systemd session detected — enable the timer after login with: systemctl --user enable --now mbsync.timer"
    fi
else
    warn "Could not create ~/.config/systemd/user — skipping the mbsync timer (set it up after first login)."
fi

# ── initial sync ──────────────────────────────────────────────────────────────
# Also best-effort: with placeholder credentials or no network at install time
# the first sync is expected to fail. Warn rather than abort so the module still
# reports success — the timer (or a manual `mbsync -a`) will sync once the user
# has filled in real account details.
log "Running initial mail sync..."
# -a syncs all configured channels; may take several minutes on a large mailbox.
if mbsync -a; then
    # Index the freshly downloaded messages so alot can display them immediately.
    notmuch new || warn "notmuch new failed — index later with: notmuch new"
else
    warn "Initial mail sync failed (credentials/network not ready) — run 'mbsync -a && notmuch new' once configured."
fi

log "Mail setup complete. Syncs automatically every 5 min via systemd timer."
log "Open alot with: alot   |   Check timer: systemctl --user status mbsync.timer"
