<?php

declare(strict_types=1);

namespace App\Service;

use App\Entity\TagRebuildJob;
use Doctrine\ORM\EntityManagerInterface;

final readonly class TagRebuildStatusProvider
{
    public function __construct(
        private EntityManagerInterface $em
    ) {
    }

    public function getLatestStatus(): ?array
    {
        $row = $this->em->createQueryBuilder()
            ->select(
                'j.status AS status',
                'j.createdAt AS createdAt',
                'j.startedAt AS startedAt',
                'j.finishedAt AS finishedAt',
                'j.errorMessage AS errorMessage'
            )
            ->from(TagRebuildJob::class, 'j')
            ->orderBy('j.createdAt', 'DESC')
            ->addOrderBy('j.id', 'DESC')
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);

        if (!is_array($row)) {
            return null;
        }

        $status = trim((string) ($row['status'] ?? ''));

        if ($status === '') {
            return null;
        }

        return [
            'status' => $status,
            'createdAt' => $this->formatDateValue($row['createdAt'] ?? null),
            'startedAt' => $this->formatDateValue($row['startedAt'] ?? null),
            'finishedAt' => $this->formatDateValue($row['finishedAt'] ?? null),
            'error' => $this->normalizeNullableString($row['errorMessage'] ?? null),
            'hasActiveJob' => in_array($status, [
                TagRebuildJob::STATUS_QUEUED,
                TagRebuildJob::STATUS_RUNNING,
            ], true),
        ];
    }

    private function formatDateValue(mixed $value): ?string
    {
        if ($value instanceof \DateTimeInterface) {
            return $value->format(DATE_ATOM);
        }

        if (is_string($value)) {
            $value = trim($value);

            if ($value === '') {
                return null;
            }

            try {
                return (new \DateTimeImmutable($value))->format(DATE_ATOM);
            } catch (\Throwable) {
                return null;
            }
        }

        return null;
    }

    private function normalizeNullableString(mixed $value): ?string
    {
        $value = trim((string) $value);

        return $value !== '' ? $value : null;
    }
}