<?php

namespace Velis\Http\Response;

use DateTime;
use Exception;
use Velis\Filesystem\FilesystemInterface;
use Velis\Http\Response;
use Velis\Mvc\Controller\Exception\BadRequestException;

/**
 * @author Jan Małysiak <jan.malysiak@velistech.com>
 */
class CachedFileResponseBuilder
{
    private Response $response;

    private FilesystemInterface $filesystem;

    /**
     * @param Response $response
     * @param FilesystemInterface $filesystem
     */
    public function __construct(Response $response, FilesystemInterface $filesystem)
    {
        $this->response = $response;
        $this->filesystem = $filesystem;
    }

    /**
     * @param string $path
     * @param bool $useCache
     * @param string|null $ifModifiedSince
     * @param string $expireAfter
     * @return Response
     * @throws Exception
     */
    public function getResponse(string $path, bool $useCache = true, string $ifModifiedSince = null, string $expireAfter = '1 year'): Response
    {
        $lastModifiedTimestamp = $this->filesystem->mtime($path);
        $lastModified = new DateTime();
        $lastModified = $lastModified->setTimestamp($lastModifiedTimestamp);

        if (is_string($ifModifiedSince) && strtotime($ifModifiedSince) === false) {
            throw new BadRequestException("Invalid date format: $ifModifiedSince");
        }

        $ifModifiedSince = $ifModifiedSince ? new DateTime($ifModifiedSince) : null;

        $expires = new DateTime();
        $expires->modify('+' . $expireAfter);

        if ($ifModifiedSince && $ifModifiedSince >= $lastModified) {
            $this->response
                ->setHeader('Cache-Control', 'private, max-age=31536000')
                ->setStatusCode(304, 'Not Modified')
                ->setExpires($expires)
            ;
        } else {
            $mimeType = $this->filesystem->mimeType($path);

            $this->response
                ->setContentType($mimeType)
                ->setContent($this->filesystem->read($path))
            ;

            if ($useCache) {
                $this->response
                    ->setHeader('Cache-Control', 'private, max-age=31536000')
                    ->setHeader('Last-Modified', $lastModified->format('r'))
                    ->setExpires($expires)
                ;
            }
        }

        return $this->response;
    }
}
