<?php

namespace App\Services\Mail;

use App\Support\Settings;
use Illuminate\Support\Carbon;

/**
 * When the support mailbox was last reached, and what came back.
 *
 * A settings row rather than a table: there is exactly one mailbox and exactly
 * one last answer, and a table of one row is a table somebody has to prune.
 *
 * Written by both callers on purpose — the operator's test button and the
 * scheduled fetch. Otherwise "last checked" would mean "last time somebody
 * pressed the button", which is the least interesting of the two: a mailbox
 * that stopped answering at three in the morning is what an operator needs to
 * see, and nobody presses a button at three in the morning.
 */
class InboundMailStatus
{
    private const KEY = 'inbound_mail.last_check';

    /** @param  int|null  $unseen  how many unread messages were waiting, where that was asked */
    public function record(bool $ok, string $message = '', ?int $unseen = null): void
    {
        Settings::set(self::KEY, [
            'at' => Carbon::now()->toIso8601String(),
            'ok' => $ok,
            // Never the password, never the whole exception: this ends up on a
            // page, and an IMAP error can quote the command it failed on.
            'message' => mb_substr($message, 0, 300),
            'unseen' => $unseen,
        ]);
    }

    /**
     * The last answer, or null if nobody has ever asked.
     *
     * @return array{at: Carbon, ok: bool, message: string, unseen: int|null}|null
     */
    public function last(): ?array
    {
        $row = Settings::get(self::KEY);

        if (! is_array($row) || ! isset($row['at'])) {
            return null;
        }

        return [
            // Parsed back into a Carbon so the view can put it on the wall clock
            // (R19) rather than printing an ISO string at somebody.
            'at' => Carbon::parse((string) $row['at']),
            'ok' => (bool) ($row['ok'] ?? false),
            'message' => (string) ($row['message'] ?? ''),
            'unseen' => isset($row['unseen']) ? (int) $row['unseen'] : null,
        ];
    }
}
