<?php

namespace App\Services;

use App\Models\RPublication;
use App\Models\RPublicationFile;
use App\Models\RReviewFeedback;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

/**
 * Service: SubmissionService
 * 
 * Handles multi-step form processing for research publications.
 * Orchestrates draft saving, file uploads, and submission workflow.
 * 
 * @author SSHIA Development Team
 * @version 1.0.0
 */
class SubmissionService
{
    /**
     * Storage disk for publication files.
     */
    protected string $disk = 'private';

    /**
     * Allowed file types.
     */
    protected array $allowedTypes = ['pdf', 'doc', 'docx', 'png', 'jpg', 'jpeg'];

    /**
     * Maximum file size in kilobytes (10MB).
     */
    protected int $maxFileSize = 10240;

    /**
     * Create a new publication draft.
     */
    public function createDraft(array $data, int $userId): RPublication
    {
        return DB::transaction(function () use ($data, $userId) {
            $publication = RPublication::create([
                'user_id' => $userId,
                'title' => $data['title'] ?? 'Untitled Draft',
                'abstract' => $data['abstract'] ?? null,
                'methodology' => $data['methodology'] ?? null,
                'findings' => $data['findings'] ?? null,
                'references' => $data['references'] ?? null,
                'category' => $data['category'] ?? 'tech',
                'status' => RPublication::STATUS_DRAFT,
            ]);

            // Save draft data to session for multi-step form restoration
            $this->saveDraftToSession($publication->id, $data);

            return $publication;
        });
    }

    /**
     * Update publication draft.
     */
    public function updateDraft(RPublication $publication, array $data): RPublication
    {
        if (!$publication->isEditable()) {
            throw new \Exception('Publication cannot be edited in its current status.');
        }

        $publication->update([
            'title' => $data['title'] ?? $publication->title,
            'abstract' => $data['abstract'] ?? $publication->abstract,
            'methodology' => $data['methodology'] ?? $publication->methodology,
            'findings' => $data['findings'] ?? $publication->findings,
            'references' => $data['references'] ?? $publication->references,
            'category' => $data['category'] ?? $publication->category,
        ]);

        // Update session data
        $this->saveDraftToSession($publication->id, $data);

        return $publication->fresh();
    }

    /**
     * Save draft data to session.
     */
    protected function saveDraftToSession(int $publicationId, array $data): void
    {
        session()->put("publication_draft.{$publicationId}", $data);
    }

    /**
     * Get draft data from session.
     */
    public function getDraftFromSession(int $publicationId): ?array
    {
        return session()->get("publication_draft.{$publicationId}");
    }

    /**
     * Clear draft data from session.
     */
    public function clearDraftSession(int $publicationId): void
    {
        session()->forget("publication_draft.{$publicationId}");
    }

    /**
     * Upload file for publication.
     */
    public function uploadFile(RPublication $publication, UploadedFile $file, array $options = []): RPublicationFile
    {
        // Validate file
        $this->validateFile($file);

        return DB::transaction(function () use ($publication, $file, $options) {
            $originalName = $file->getClientOriginalName();
            $extension = strtolower($file->getClientOriginalExtension());
            $storedName = Str::random(40) . '.' . $extension;
            $filePath = "publications/{$publication->id}/{$storedName}";

            // Store file
            $path = Storage::disk($this->disk)->putFileAs(
                "publications/{$publication->id}",
                $file,
                $storedName
            );

            // Determine file type
            $fileType = $this->determineFileType($extension);

            // Create file record
            $publicationFile = RPublicationFile::create([
                'publication_id' => $publication->id,
                'original_name' => $originalName,
                'stored_name' => $storedName,
                'file_path' => $path,
                'file_size' => $file->getSize(),
                'mime_type' => $file->getMimeType(),
                'file_type' => $fileType,
                'is_public' => $options['is_public'] ?? false,
                'version' => 1,
                'description' => $options['description'] ?? null,
            ]);

            return $publicationFile;
        });
    }

    /**
     * Delete file from publication.
     */
    public function deleteFile(RPublicationFile $file): bool
    {
        return DB::transaction(function () use ($file) {
            // Delete from storage
            if (Storage::disk($this->disk)->exists($file->file_path)) {
                Storage::disk($this->disk)->delete($file->file_path);
            }

            return $file->delete();
        });
    }

    /**
     * Submit publication for review.
     */
    public function submitForReview(RPublication $publication): RPublication
    {
        if (!$publication->canSubmit()) {
            throw new \Exception('Publication cannot be submitted for review.');
        }

        // Validate required fields
        $this->validateForSubmission($publication);

        return DB::transaction(function () use ($publication) {
            $publication->update([
                'status' => RPublication::STATUS_UNDER_REVIEW,
                'submitted_at' => now(),
            ]);

            // Clear draft session
            $this->clearDraftSession($publication->id);

            // TODO: Send notification to reviewers

            return $publication->fresh();
        });
    }

    /**
     * Resubmit after revision.
     */
    public function resubmitAfterRevision(RPublication $publication, array $data = []): RPublication
    {
        if ($publication->status !== RPublication::STATUS_REVISION_REQUIRED) {
            throw new \Exception('Publication is not pending revision.');
        }

        DB::transaction(function () use ($publication, $data) {
            // Update data if provided
            if (!empty($data)) {
                $publication->update($data);
            }

            $publication->update([
                'status' => RPublication::STATUS_UNDER_REVIEW,
            ]);

            // TODO: Notify reviewers of resubmission
        });

        return $publication->fresh();
    }

    /**
     * Validate file before upload.
     */
    protected function validateFile(UploadedFile $file): void
    {
        $extension = strtolower($file->getClientOriginalExtension());

        if (!in_array($extension, $this->allowedTypes)) {
            throw new \InvalidArgumentException(
                'Invalid file type. Allowed types: ' . implode(', ', $this->allowedTypes)
            );
        }

        if ($file->getSize() > $this->maxFileSize * 1024) {
            throw new \InvalidArgumentException(
                'File size exceeds maximum allowed size of ' . ($this->maxFileSize / 1024) . 'MB'
            );
        }
    }

    /**
     * Determine file type from extension.
     */
    protected function determineFileType(string $extension): string
    {
        return match ($extension) {
            'pdf' => RPublicationFile::TYPE_PDF,
            'doc' => RPublicationFile::TYPE_DOC,
            'docx' => RPublicationFile::TYPE_DOCX,
            'png', 'jpg', 'jpeg', 'gif', 'webp' => RPublicationFile::TYPE_IMAGE,
            default => RPublicationFile::TYPE_OTHER,
        };
    }

    /**
     * Validate publication for submission.
     * Only title and abstract are strictly required.
     * Methodology, findings, and files are recommended but not blocking.
     */
    protected function validateForSubmission(RPublication $publication): void
    {
        $errors = [];

        if (empty($publication->title)) {
            $errors[] = 'Title is required.';
        }

        if (empty($publication->abstract)) {
            $errors[] = 'Abstract is required.';
        }

        if (!empty($errors)) {
            throw new \InvalidArgumentException(implode(' ', $errors));
        }
    }

    /**
     * Get publications by user.
     */
    public function getUserPublications(int $userId, array $filters = [])
    {
        $query = RPublication::byUser($userId)
                           ->with(['files', 'reviews'])
                           ->latest();

        // Apply filters
        if (!empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        if (!empty($filters['category'])) {
            $query->where('category', $filters['category']);
        }

        return $query->paginate($filters['per_page'] ?? 15);
    }

    /**
     * Get publication statistics for user.
     */
    public function getUserStats(int $userId): array
    {
        return [
            'total' => RPublication::byUser($userId)->count(),
            'drafts' => RPublication::byUser($userId)->where('status', RPublication::STATUS_DRAFT)->count(),
            'under_review' => RPublication::byUser($userId)->where('status', RPublication::STATUS_UNDER_REVIEW)->count(),
            'approved' => RPublication::byUser($userId)->whereIn('status', [RPublication::STATUS_APPROVED, RPublication::STATUS_FEATURED])->count(),
            'revision_required' => RPublication::byUser($userId)->where('status', RPublication::STATUS_REVISION_REQUIRED)->count(),
        ];
    }
}
