<?php

declare(strict_types=1);

namespace App\Uploads\Services;

use App\Models\Artwork;
use App\Models\User;
use App\Uploads\Exceptions\DraftQuotaException;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;

final class DraftQuotaService
{
    /**
     * @param array{files:array<int, UploadedFile>, main_hash:string} $incomingFiles
     * @return array<int, string>
     */
    public function assertCanCreateDraft(User $user, array $incomingFiles): array
    {
        $maxDrafts = max(1, (int) config('uploads.draft_quota.max_drafts_per_user', 10));
        $maxStorageMb = max(1, (int) config('uploads.draft_quota.max_draft_storage_mb_per_user', 1024));
        $maxStorageBytes = $maxStorageMb * 1024 * 1024;
        $policy = (string) config('uploads.draft_quota.duplicate_hash_policy', 'block');
        $warnings = [];

        $draftCount = DB::table('uploads')
            ->where('user_id', (int) $user->id)
            ->where('status', 'draft')
            ->count();

        if ($draftCount >= $maxDrafts) {
            throw DraftQuotaException::draftLimit();
        }

        $currentDraftStorage = (int) DB::table('upload_files as uf')
            ->join('uploads as u', 'u.id', '=', 'uf.upload_id')
            ->where('u.user_id', (int) $user->id)
            ->where('u.status', 'draft')
            ->sum(DB::raw('COALESCE(uf.size, 0)'));

        $incomingSize = $this->incomingSizeBytes((array) ($incomingFiles['files'] ?? []));

        if (($currentDraftStorage + $incomingSize) > $maxStorageBytes) {
            throw DraftQuotaException::storageLimit();
        }

        $mainHash = strtolower(trim((string) ($incomingFiles['main_hash'] ?? '')));
        if ($mainHash !== '' && $this->publishedMainHashExists($mainHash)) {
            if ($policy === 'warn') {
                $warnings[] = 'duplicate_hash';
            } else {
                throw DraftQuotaException::duplicateUpload();
            }
        }

        return $warnings;
    }

    /**
     * @param array<int, UploadedFile> $files
     */
    private function incomingSizeBytes(array $files): int
    {
        $total = 0;

        foreach ($files as $file) {
            if (! $file instanceof UploadedFile) {
                continue;
            }

            $size = $file->getSize();
            if (is_numeric($size)) {
                $total += (int) $size;
            }
        }

        return max(0, $total);
    }

    private function publishedMainHashExists(string $hash): bool
    {
        return Artwork::query()
            ->where('hash', $hash)
            ->where('artwork_status', 'published')
            ->whereNotNull('published_at')
            ->exists();
    }
}
