<?php

namespace App\Services;

use App\Models\Document;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

class DocumentService
{
    /**
     * Upload a document for any model.
     */
    public function uploadDocument(
        Model $model,
        UploadedFile $file,
        string $documentType = 'general',
        ?string $description = null
    ): Document {
        $fileName = time().'_'.$file->getClientOriginalName();
        $folderName = strtolower(class_basename($model));
        $filePath = $file->storeAs("documents/{$folderName}", $fileName, Document::STORAGE_DISK);

        return $model->documents()->create([
            'name' => $file->getClientOriginalName(),
            'path' => $filePath,
            'file_size' => $file->getSize(),
            'mime_type' => $file->getClientMimeType(),
            'type' => $documentType,
            'description' => $description,
            'uploaded_by' => auth()->id(),
        ]);
    }

    /**
     * Delete a document.
     */
    public function deleteDocument(string $documentId): bool
    {
        $document = Document::findOrFail($documentId);

        return $document->delete();
    }

    /**
     * Get all documents for a model.
     */
    public function getDocuments(Model $model, ?string $documentType = null)
    {
        $query = $model->documents();

        if ($documentType) {
            $query->where('type', $documentType);
        }

        return $query->with('uploadedBy')->get();
    }

    /**
     * Get document by ID with validation.
     */
    public function getDocument(string $documentId): Document
    {
        return Document::with('uploadedBy')->findOrFail($documentId);
    }

    /**
     * Download a document.
     */
    public function downloadDocument(string $documentId)
    {
        $document = $this->getDocument($documentId);

        $disk = Storage::disk(Document::STORAGE_DISK);

        if (! $disk->exists($document->path)) {
            throw new Exception('File not found');
        }

        return $disk->download($document->path, $document->name);
    }

    /**
     * Get documents count for a model.
     */
    public function getDocumentsCount(Model $model, ?string $documentType = null): int
    {
        $query = $model->documents();

        if ($documentType) {
            $query->where('type', $documentType);
        }

        return $query->count();
    }

    /**
     * Check if model has documents.
     */
    public function hasDocuments(Model $model, ?string $documentType = null): bool
    {
        return $this->getDocumentsCount($model, $documentType) > 0;
    }

    /**
     * Get supported file types.
     */
    public function getSupportedFileTypes(): array
    {
        return [
            'pdf' => 'application/pdf',
            'doc' => 'application/msword',
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'jpg' => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif',
        ];
    }

    /**
     * Get max file size in KB.
     */
    public function getMaxFileSize(): int
    {
        return 10240; // 10MB
    }

    /**
     * Validate file upload.
     */
    public function validateFile(UploadedFile $file): bool
    {
        $supportedTypes = $this->getSupportedFileTypes();
        $maxSize = $this->getMaxFileSize() * 1024; // Convert to bytes

        if ($file->getSize() > $maxSize) {
            throw new Exception('File size exceeds maximum limit of '.$this->getMaxFileSize().'KB');
        }

        if (! in_array($file->getClientMimeType(), $supportedTypes)) {
            throw new Exception('File type not supported. Supported types: '.implode(', ', array_keys($supportedTypes)));
        }

        return true;
    }

    /**
     * Bulk delete documents for a model.
     */
    public function bulkDeleteDocuments(Model $model, array $documentIds): int
    {
        $deletedCount = 0;

        foreach ($documentIds as $documentId) {
            $document = $model->documents()->find($documentId);

            if ($document) {
                $document->delete();
                $deletedCount++;
            }
        }

        return $deletedCount;
    }
}
