<?php
/**
 * Copyright © Simplyin. All rights reserved.
 */
declare(strict_types=1);

namespace Simplyin\Payment\Service;

use Psr\Log\LoggerInterface;

/**
 * Formats a Magento order timestamp (persisted UTC, e.g. created_at) into the
 * ISO 8601 UTC-with-microseconds contract shared with statusInfo.statusDate
 * ('Y-m-d\TH:i:s.u\Z').
 *
 * Shared by the order-sync payload (OrderPayloadBuilder) and the live-checkout
 * CreateOrder flow so the orderDate format cannot drift between the two paths.
 */
class OrderDateFormatter
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @param LoggerInterface $logger
     */
    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    /**
     * Parse a Magento DB timestamp and format it to the orderDate contract.
     * Returns null when the input is empty or unparseable, so the (optional)
     * field is simply omitted from the payload rather than sending garbage.
     *
     * @param string|null $timestamp
     * @return string|null
     */
    public function format(?string $timestamp): ?string
    {
        if ($timestamp === null || trim($timestamp) === '') {
            return null;
        }

        // MySQL zero-dates ('0000-00-00 00:00:00') are not rejected by
        // \DateTime — it silently parses them into a bogus -0001-11-30
        // timestamp instead of throwing. Reject them explicitly up front.
        if (preg_match('/^0{4}-0{2}-0{2}/', trim($timestamp)) === 1) {
            $this->logger->debug('SimplyIN: rejected zero-date order timestamp "' . $timestamp . '"');
            return null;
        }

        try {
            // Magento persists order timestamps in UTC regardless of store
            // timezone, so no store-timezone conversion is needed here.
            $date = new \DateTime($timestamp, new \DateTimeZone('UTC'));
        } catch (\Exception $e) {
            $this->logger->debug('SimplyIN: could not parse order timestamp "' . $timestamp . '": ' . $e->getMessage());
            return null;
        }

        // Belt-and-braces: a year <= 0 means the zero-date (or similar
        // garbage) slipped through the regex guard above (e.g. leading
        // whitespace) and was parsed into a bogus date rather than throwing.
        if ((int) $date->format('Y') <= 0) {
            $this->logger->debug('SimplyIN: rejected out-of-range order timestamp "' . $timestamp . '"');
            return null;
        }

        // \DateTime's constructor timezone argument is ignored whenever the
        // input string itself carries an offset/timezone (e.g. "+02:00" or
        // a trailing "Z"), so the parsed instant can be in a non-UTC zone.
        // Convert explicitly to keep the UTC guarantee this shared
        // formatter promises to its callers.
        $date->setTimezone(new \DateTimeZone('UTC'));

        return $date->format('Y-m-d\TH:i:s.u\Z');
    }
}
