<?php

namespace App\Domain\System\Application\QueryHandler;

use App\Domain\Shared\Domain\Contract\JobRepositoryInterface;
use App\Domain\Shared\Domain\Model\JobStatus;
use App\Domain\System\Application\Query\GetSystemStatusQuery;
use App\Domain\System\Domain\Contract\Repository\SystemStatusRepositoryInterface;
use App\Domain\System\Domain\Model\SystemStatus;

readonly class GetSystemStatusQueryHandler
{
    public function __construct(
        private SystemStatusRepositoryInterface $systemStatusRepository,
        private JobRepositoryInterface $jobRepository,
        private string $mangaDataPath,
        private string $imagesStoragePath,
    ) {
    }

    public function handle(GetSystemStatusQuery $query): SystemStatus
    {
        $now = new \DateTimeImmutable();
        $last24h = $now->modify('-24 hours');
        $last7d = $now->modify('-7 days');

        $totalJobs = $this->jobRepository->countByCriteria([]);
        $completedJobs = $this->jobRepository->countByCriteria(['status' => JobStatus::COMPLETED]);
        $failedJobs = $this->jobRepository->countByCriteria(['status' => JobStatus::FAILED]);
        $pendingJobs = $this->jobRepository->countByCriteria(['status' => JobStatus::PENDING]);
        $inProgressJobs = $this->jobRepository->countByCriteria(['status' => JobStatus::IN_PROGRESS]);

        $totalJobsLast24h = $this->jobRepository->countByCriteria(['createdAfter' => $last24h]);
        $completedJobsLast24h = $this->jobRepository->countByCriteria(['status' => JobStatus::COMPLETED, 'createdAfter' => $last24h]);
        $failedJobsLast24h = $this->jobRepository->countByCriteria(['status' => JobStatus::FAILED, 'createdAfter' => $last24h]);

        $totalJobsLast7d = $this->jobRepository->countByCriteria(['createdAfter' => $last7d]);
        $completedJobsLast7d = $this->jobRepository->countByCriteria(['status' => JobStatus::COMPLETED, 'createdAfter' => $last7d]);
        $failedJobsLast7d = $this->jobRepository->countByCriteria(['status' => JobStatus::FAILED, 'createdAfter' => $last7d]);

        $storagePath = $this->imagesStoragePath;
        $storageTotalBytes = (int) (@disk_total_space($storagePath) ?: 0);
        $storageFreeBytes = (int) (@disk_free_space($storagePath) ?: 0);
        $storageUsedBytes = $this->computeDirectorySize($storagePath);

        return new SystemStatus(
            totalMangas: $this->systemStatusRepository->countMangas(),
            monitoredMangas: $this->systemStatusRepository->countMonitoredMangas(),
            mangasByStatus: $this->systemStatusRepository->countMangasByStatus(),
            totalChapters: $this->systemStatusRepository->countChapters(),
            downloadedChapters: $this->systemStatusRepository->countDownloadedChapters(),
            totalJobs: $totalJobs,
            completedJobs: $completedJobs,
            failedJobs: $failedJobs,
            pendingJobs: $pendingJobs,
            inProgressJobs: $inProgressJobs,
            totalJobsLast24h: $totalJobsLast24h,
            completedJobsLast24h: $completedJobsLast24h,
            failedJobsLast24h: $failedJobsLast24h,
            totalJobsLast7d: $totalJobsLast7d,
            completedJobsLast7d: $completedJobsLast7d,
            failedJobsLast7d: $failedJobsLast7d,
            storagePath: $this->mangaDataPath,
            storageTotalBytes: $storageTotalBytes,
            storageFreeBytes: $storageFreeBytes,
            storageUsedBytes: $storageUsedBytes,
            totalSources: $this->systemStatusRepository->countContentSources(),
            sourcesByHealth: $this->systemStatusRepository->countContentSourcesByHealth(),
            phpVersion: PHP_VERSION,
            generatedAt: $now,
        );
    }

    private function computeDirectorySize(string $path): int
    {
        if (!is_dir($path)) {
            return 0;
        }

        $size = 0;
        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS)
        );

        foreach ($iterator as $file) {
            if ($file->isFile()) {
                $size += $file->getSize();
            }
        }

        return $size;
    }
}
