<?php

declare(strict_types=1);

namespace MauticPlugin\DealFlowBundle\Service;

use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class AttachmentStorage
{
    public function __construct(
        private readonly CoreParametersHelper $coreParametersHelper,
    ) {
    }

    /**
     * @return array{storagePath:string,mimeType:string,sizeBytes:int,originalFilename:string}
     */
    public function store(UploadedFile $file): array
    {
        $this->validate($file);

        $mimeType = $file->getMimeType() ?: $file->getClientMimeType() ?: 'application/octet-stream';
        $baseDir = rtrim((string) $this->coreParametersHelper->get('dealflow_upload_dir'), '/');
        $hash = sha1(uniqid((string) mt_rand(), true));
        $subdir = substr($hash, 0, 2).'/'.substr($hash, 2, 2);
        $filename = $hash.'.'.$file->guessExtension();
        $target = $baseDir.'/'.$subdir;

        if (!is_dir($target) && !mkdir($target, 0775, true) && !is_dir($target)) {
            throw new \RuntimeException(sprintf('Unable to create attachment directory "%s".', $target));
        }

        $storedFile = $file->move($target, $filename);

        return [
            'storagePath' => $subdir.'/'.$storedFile->getFilename(),
            'mimeType' => $mimeType,
            'sizeBytes' => (int) $storedFile->getSize(),
            'originalFilename' => $file->getClientOriginalName(),
        ];
    }

    /**
     * @return array{storagePath:string,mimeType:string,sizeBytes:int,originalFilename:string}
     */
    public function storeFromPath(string $sourcePath, string $originalFilename): array
    {
        if (!is_file($sourcePath)) {
            throw new \RuntimeException(sprintf('Source file "%s" does not exist.', $sourcePath));
        }

        $mimeType = mime_content_type($sourcePath) ?: 'application/octet-stream';
        $sizeBytes = (int) filesize($sourcePath);

        $baseDir = rtrim((string) $this->coreParametersHelper->get('dealflow_upload_dir'), '/');
        $hash = sha1(uniqid((string) mt_rand(), true));
        $subdir = substr($hash, 0, 2).'/'.substr($hash, 2, 2);
        $extension = pathinfo($originalFilename, PATHINFO_EXTENSION) ?: pathinfo($sourcePath, PATHINFO_EXTENSION) ?: 'bin';
        $filename = $hash.'.'.$extension;
        $target = $baseDir.'/'.$subdir;

        if (!is_dir($target) && !mkdir($target, 0775, true) && !is_dir($target)) {
            throw new \RuntimeException(sprintf('Unable to create attachment directory "%s".', $target));
        }

        if (!copy($sourcePath, $target.'/'.$filename)) {
            throw new \RuntimeException(sprintf('Failed to copy file from "%s".', $sourcePath));
        }

        return [
            'storagePath' => $subdir.'/'.$filename,
            'mimeType' => $mimeType,
            'sizeBytes' => $sizeBytes,
            'originalFilename' => $originalFilename,
        ];
    }

    public function getAbsolutePath(string $storagePath): string
    {
        return rtrim((string) $this->coreParametersHelper->get('dealflow_upload_dir'), '/').'/'.ltrim($storagePath, '/');
    }

    public function delete(string $storagePath): void
    {
        $path = $this->getAbsolutePath($storagePath);

        if (is_file($path)) {
            @unlink($path);
        }
    }

    public function validate(UploadedFile $file): void
    {
        $maxBytes = (int) $this->coreParametersHelper->get('dealflow_max_attachment_size_mb') * 1024 * 1024;
        $allowedMimeTypes = (array) $this->coreParametersHelper->get('dealflow_allowed_mime_types');
        $mimeType = $file->getMimeType() ?: $file->getClientMimeType() ?: 'application/octet-stream';

        if ($file->getSize() > $maxBytes) {
            throw new \RuntimeException('Attachment exceeds the maximum allowed file size.');
        }

        if (!in_array($mimeType, $allowedMimeTypes, true)) {
            throw new \RuntimeException('Attachment type is not allowed.');
        }
    }
}
