<?php

declare(strict_types=1);

namespace Plugin\tnt_stabila_shop\src\Services;

use JTL\Router\Route;
use JTL\ServiceReport\Report\Factory;
use JTL\Shop;
use Plugin\tnt_stabila_shop\src\Repositories\ReportRepository;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\VarDumper;

class ReportService extends \JTL\ServiceReport\ReportService
{
    private string $reportID;
    public function __construct(private readonly ReportRepository $repository)
    {
        parent::__construct(Shop::Container()->getPasswordService());
    }

    /**
     * @return object{link: string, maxDate: string}
     * @throws \JsonException
     */
    public function generateAndSaveReport(string $reportName, string $adminURL): object
    {
        $this->reportID = 'report_stabila_' . $reportName . '_' . \date('YmdHis');
        $data           = [];
        $factory        = new Factory();
        if (
            !\is_dir(self::BASE_PATH)
            && !\mkdir(self::BASE_PATH, 0755, true)
            && !\is_dir(self::BASE_PATH)
        ) {
            throw new \RuntimeException(
                \sprintf(\__('Directory %s could not be created'), self::BASE_PATH)
            );
        }
        foreach ($factory->getReports() as $report) {
            $data[\get_class($report)] = $report->getData();
        }
        $rawJson = \json_encode($data, \JSON_PRETTY_PRINT | \JSON_THROW_ON_ERROR);
        $file    = self::BASE_PATH . $this->reportID . '.json';
        if (\file_put_contents($file, $rawJson) === false) {
            throw new \RuntimeException(\sprintf(\__('Could not write report data to file %s'), $file));
        }
        VarDumper::setHandler($this->dumpHandler(...));
        \dump($data);
        $report  = (object)[
            'id'      => 0,
            'file'    => $this->reportID,
            'created' => 'NOW()',
            'hash'    => '',
        ];
        $report->id = $this->repository->addReport($report);
        try {
            $report->hash = $this->authorize($report->id);
        } catch (\Exception $e) {
            Shop::Container()->getAlertService()->addError(
                \sprintf(\__('Report could not be authorized: %s.'), $e->getMessage()),
                'authorize-error'
            );
        }
        $this->repository->updateAuthorizationData($report->id, $report->hash);

        return (object)[
            'link'    => $adminURL . '/' . Route::REPORT_VIEW . '/' . $report->hash,
            'maxDate' => \date('Y-m-d H:i:s', \strtotime('+7 days')),
        ];
    }

    public function removeOldPluginReports(int $preserveLastXItems = 3): void
    {
        $reports = $this->repository->getPluginReports();
        foreach ($reports as $offset => $report) {
            if ($offset < $preserveLastXItems) {
                continue;
            }
            $this->deleteReport($report);
        }
    }

    public function reportAlreadyExists(string $reportName): bool
    {
        return $this->repository->reportAlreadyExists($reportName);
    }

    private function dumpHandler(mixed $var): ?string
    {
        $outputFile = self::BASE_PATH . $this->reportID . '.html';
        $output     = \fopen($outputFile, 'wb');
        if ($output === false) {
            throw new \RuntimeException(\sprintf(\__('Could not open report dump file %s'), $outputFile));
        }
        $cloner = new VarCloner();
        $cloner->setMinDepth(10);

        return (new HtmlDumper($output))->dump($cloner->cloneVar($var), $output);
    }

    public function deleteReport(object $report): bool
    {
        /** @var object{file: string, id: int|string} $report */
        $path = self::BASE_PATH . $report->file;
        foreach (['.html', '.json'] as $ext) {
            if (\file_exists($path . $ext)) {
                \unlink($path . $ext);
            }
        }

        return $this->repository->delete((int)$report->id);
    }
}
