<?php

namespace App\Http\Controllers\Research;

use App\Http\Controllers\Controller;
use App\Models\RPublication;
use App\Services\SubmissionService;
use App\Services\PublicationSearchService;
use App\Http\Requests\Research\StorePublicationRequest;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\View\View;

/**
 * Controller: RPublicationController
 * 
 * Handles CRUD operations for research publications with support for
 * both public showcase and authenticated dashboard views.
 * 
 * @author SSHIA Development Team
 * @version 1.0.0
 */
class RPublicationController extends Controller
{
    /**
     * Create a new controller instance.
     */
    public function __construct(
        protected SubmissionService $submissionService,
        protected PublicationSearchService $searchService
    ) {}

    /**
     * Display public showcase of published research.
     * Public access - Site Layout
     */
    public function publicIndex(Request $request): View
    {
        $query = RPublication::published()
                           ->with(['user.roles', 'files'])
                           ->latest('approved_at');

        // Category filter
        if ($request->filled('category')) {
            $query->where('category', $request->category);
        }

        // Search
        if ($request->filled('q')) {
            $query->search($request->q);
        }

        $publications = $query->paginate(12);

        // Featured publications for hero
        $featured = RPublication::featured()
                               ->with(['user'])
                               ->limit(3)
                               ->get();

        return view('research.public.index', [
            'publications' => $publications,
            'featured' => $featured,
            'filters' => $request->only(['category', 'q']),
        ]);
    }

    /**
     * Display single publication (public view).
     * Public access - Site Layout
     */
    public function publicShow(RPublication $publication): View
    {
        // Only show approved publications
        if (!in_array($publication->status, [RPublication::STATUS_APPROVED, RPublication::STATUS_FEATURED])) {
            abort(404);
        }

        $publication->load(['user.roles', 'files', 'reviews' => function ($q) {
            $q->where('decision', 'approve');
        }]);

        // Get related publications
        $related = $this->searchService->getRelatedPublications($publication);

        return view('research.public.show', [
            'publication' => $publication,
            'related' => $related,
        ]);
    }

    /**
     * Display user's publications in dashboard.
     * Authenticated - App Layout
     */
    public function index(Request $request): View
    {
        abort_unless(auth()->user()->can('view own publications'), 403);

        $publications = $this->submissionService->getUserPublications(
            auth()->id(),
            $request->only(['status', 'category', 'per_page'])
        );

        $stats = $this->submissionService->getUserStats(auth()->id());

        return view('research.index', [
            'publications' => $publications,
            'stats' => $stats,
            'filters' => $request->only(['status', 'category']),
        ]);
    }

    /**
     * Show the form for creating a new publication.
     * Authenticated - App Layout
     */
    public function create(): View
    {
        abort_unless(auth()->user()->can('create publications'), 403);

        // Check for draft in session
        $draftId = session('current_draft_id');
        $draftData = $draftId ? $this->submissionService->getDraftFromSession($draftId) : null;

        return view('research.create', [
            'draftData' => $draftData,
            'categories' => [
                'clinical' => 'Clinical Research',
                'tech' => 'Technology & Innovation',
                'social' => 'Social Sciences',
            ],
        ]);
    }

    /**
     * Store a newly created publication.
     */
    public function store(StorePublicationRequest $request): mixed
    {
        abort_unless(auth()->user()->can('create publications'), 403);

        try {
            $publication = $this->submissionService->createDraft(
                $request->validated(),
                auth()->id()
            );

            // Handle file uploads
            if ($request->hasFile('files')) {
                foreach ($request->file('files') as $file) {
                    $this->submissionService->uploadFile($publication, $file);
                }
            }

            // Handle cover image
            if ($request->hasFile('cover_image')) {
                $path = $request->file('cover_image')->store('publications/covers', 'public');
                $publication->update(['cover_image' => $path]);
            }

            // Auto-submit or save as draft
            if ($request->input('action') === 'submit') {
                $this->submissionService->submitForReview($publication);
                
                return redirect()
                    ->route('research.index')
                    ->with('success', 'Publication submitted for review successfully!');
            }

            return redirect()
                ->route('research.edit', $publication)
                ->with('success', 'Draft saved successfully!');

        } catch (\Exception $e) {
            return back()
                ->withInput()
                ->with('error', 'Failed to save publication: ' . $e->getMessage());
        }
    }

    /**
     * Display the specified publication.
     */
    public function show(RPublication $publication): View
    {
        // Author can view own publications
        if (!$publication->isAuthor(auth()->id())) {
            abort_unless(auth()->user()->can('view publications'), 403);
        }

        $publication->load(['user', 'files', 'reviews.reviewer']);

        return view('research.show', [
            'publication' => $publication,
        ]);
    }

    /**
     * Show the form for editing the specified publication.
     */
    public function edit(RPublication $publication): View
    {
        // Only author can edit
        abort_unless($publication->isAuthor(auth()->id()), 403);
        
        // Check if editable
        if (!$publication->isEditable()) {
            return redirect()
                ->route('research.show', $publication)
                ->with('error', 'This publication cannot be edited in its current status.');
        }

        $publication->load('files');

        return view('research.edit', [
            'publication' => $publication,
            'categories' => [
                'clinical' => 'Clinical Research',
                'tech' => 'Technology & Innovation',
                'social' => 'Social Sciences',
            ],
        ]);
    }

    /**
     * Update the specified publication.
     */
    public function update(StorePublicationRequest $request, RPublication $publication): mixed
    {
        abort_unless($publication->isAuthor(auth()->id()), 403);

        if (!$publication->isEditable()) {
            return back()->with('error', 'This publication cannot be edited.');
        }

        try {
            $this->submissionService->updateDraft($publication, $request->validated());

            // Handle new file uploads
            if ($request->hasFile('files')) {
                foreach ($request->file('files') as $file) {
                    $this->submissionService->uploadFile($publication, $file);
                }
            }

            // Handle cover image
            if ($request->hasFile('cover_image')) {
                $path = $request->file('cover_image')->store('publications/covers', 'public');
                $publication->update(['cover_image' => $path]);
            }

            // Auto-submit or save as draft
            if ($request->input('action') === 'submit') {
                $this->submissionService->submitForReview($publication);
                
                return redirect()
                    ->route('research.index')
                    ->with('success', 'Publication submitted for review successfully!');
            }

            return back()->with('success', 'Publication updated successfully!');

        } catch (\Exception $e) {
            return back()
                ->withInput()
                ->with('error', 'Failed to update: ' . $e->getMessage());
        }
    }

    /**
     * Remove the specified publication.
     */
    public function destroy(RPublication $publication): mixed
    {
        abort_unless($publication->isAuthor(auth()->id()) || 
                     auth()->user()->can('delete publications'), 403);

        if ($publication->status === RPublication::STATUS_UNDER_REVIEW) {
            return back()->with('error', 'Cannot delete a publication under review.');
        }

        $publication->delete();

        return redirect()
            ->route('research.index')
            ->with('success', 'Publication deleted successfully!');
    }

    /**
     * Submit publication for review.
     */
    public function submitForReview(RPublication $publication): mixed
    {
        abort_unless($publication->isAuthor(auth()->id()), 403);

        try {
            $this->submissionService->submitForReview($publication);

            return redirect()
                ->route('research.index')
                ->with('success', 'Publication submitted for review successfully!');

        } catch (\Exception $e) {
            return back()->with('error', $e->getMessage());
        }
    }

    /**
     * Delete a file from publication.
     */
    public function deleteFile(RPublication $publication, int $fileId): JsonResponse
    {
        abort_unless($publication->isAuthor(auth()->id()), 403);

        $file = $publication->files()->findOrFail($fileId);

        $this->submissionService->deleteFile($file);

        return response()->json([
            'success' => true,
            'message' => 'File deleted successfully.',
        ]);
    }

    /**
     * Show the public guest submission form (no auth required).
     * Guests fill the multi-step form; on submit they are redirected to register/login as contributor.
     */
    public function publicSubmitForm(): View
    {
        return view('research.public.submit', [
            'categories' => [
                'clinical' => 'Clinical Research',
                'tech'     => 'Technology & Innovation',
                'social'   => 'Social Sciences',
            ],
        ]);
    }

    /**
     * Store a guest publication submission.
     * Saves form data to session then redirects to contributor registration/login.
     */
    public function publicSubmitStore(\Illuminate\Http\Request $request): mixed
    {
        $validated = $request->validate([
            'title'       => ['required', 'string', 'min:10', 'max:191'],
            'abstract'    => ['required', 'string', 'min:100', 'max:5000'],
            'methodology' => ['nullable', 'string', 'max:10000'],
            'findings'    => ['nullable', 'string', 'max:10000'],
            'references'  => ['nullable', 'string', 'max:15000'],
            'category'    => ['required', 'in:clinical,tech,social'],
            'cover_image' => ['nullable', 'image', 'mimes:jpeg,png,jpg,webp', 'max:2048'],
            'full_paper'  => ['nullable', 'file', 'mimes:pdf,doc,docx', 'max:20480'],
        ]);

        // Store cover image temporarily
        if ($request->hasFile('cover_image')) {
            $validated['cover_image_path'] = $request->file('cover_image')
                ->store('publications/temp/covers', 'public');
        }

        // Store full paper temporarily
        if ($request->hasFile('full_paper')) {
            $validated['full_paper_path'] = $request->file('full_paper')
                ->store('publications/temp/papers', 'public');
            $validated['full_paper_name'] = $request->file('full_paper')->getClientOriginalName();
            $validated['full_paper_size'] = $request->file('full_paper')->getSize();
            $validated['full_paper_mime'] = $request->file('full_paper')->getMimeType();
        }

        // Persist to session so it survives the registration redirect
        session(['pending_publication' => $validated]);

        // If already authenticated as contributor, create the draft immediately
        if (auth()->check() && auth()->user()->can('create publications')) {
            return $this->createDraftFromPendingSession();
        }

        // Otherwise send to contributor registration/login choice
        return redirect()->route('research.public.submit.auth')
            ->with('info', 'Almost there! Please register as a Contributor or log in to finalise your submission.');
    }

    /**
     * Create a publication draft from the pending_publication session data.
     * Called after login/registration when a pending submission exists.
     * Route handler: GET /dashboard/research/pending/create
     */
    public function createDraftFromPendingSession(): mixed
    {
        $userId  = auth()->id();
        $pending = session('pending_publication');

        if (!$pending) {
            return redirect()->route('research.create');
        }

        try {
            $publication = $this->submissionService->createDraft([
                'title'       => $pending['title'],
                'abstract'    => $pending['abstract'],
                'methodology' => $pending['methodology'] ?? null,
                'findings'    => $pending['findings'] ?? null,
                'references'  => $pending['references'] ?? null,
                'category'    => $pending['category'],
            ], $userId);

            // Move cover image from temp to permanent location
            if (!empty($pending['cover_image_path'])) {
                $newPath = 'publications/covers/' . basename($pending['cover_image_path']);
                \Illuminate\Support\Facades\Storage::disk('public')->move(
                    $pending['cover_image_path'], $newPath
                );
                $publication->update(['cover_image' => $newPath]);
            }

            // Move full paper from temp to permanent location and create file record
            if (!empty($pending['full_paper_path'])) {
                $originalName = $pending['full_paper_name'] ?? 'paper.pdf';
                $extension    = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
                $storedName   = \Illuminate\Support\Str::random(40) . '.' . $extension;
                $newPath      = "publications/{$publication->id}/{$storedName}";

                \Illuminate\Support\Facades\Storage::disk('public')->move(
                    $pending['full_paper_path'], $newPath
                );

                \App\Models\RPublicationFile::create([
                    'publication_id' => $publication->id,
                    'original_name'  => $originalName,
                    'stored_name'    => $storedName,
                    'file_path'      => $newPath,
                    'file_size'      => $pending['full_paper_size'] ?? 0,
                    'mime_type'      => $pending['full_paper_mime'] ?? 'application/octet-stream',
                    'file_type'      => match($extension) {
                        'pdf'  => 'pdf',
                        'doc'  => 'doc',
                        'docx' => 'docx',
                        default => 'other',
                    },
                    'is_public'      => true,
                    'version'        => 1,
                ]);
            }

            // Clear the pending session
            session()->forget('pending_publication');

            return redirect()->route('research.show', $publication)
                ->with('success', 'Your submission has been saved as a draft. Review it and click "Submit for Review" when ready.');

        } catch (\Exception $e) {
            \Illuminate\Support\Facades\Log::error('Failed to create draft from pending session', [
                'user_id' => $userId,
                'error'   => $e->getMessage(),
            ]);
            return redirect()->route('research.create')
                ->with('info', 'Please complete your submission. Some details may need to be re-entered.');
        }
    }

    /**
     * Display featured publications (public).
     */
    public function featured(): View
    {
        $publications = RPublication::published()
            ->where(function ($q) {
                $q->where('is_featured', true)
                  ->orWhere('status', RPublication::STATUS_FEATURED);
            })
            ->with(['user.roles', 'files'])
            ->latest('approved_at')
            ->paginate(12);

        return view('research.public.featured', [
            'publications' => $publications,
        ]);
    }

    /**
     * Auth gateway page shown after guest completes the submission form.
     */
    public function publicSubmitAuth(): mixed
    {
        // If no pending publication, redirect back to form
        if (!session('pending_publication')) {
            return redirect()->route('research.public.submit')
                ->with('error', 'Please complete the submission form first.');
        }

        return view('research.public.submit-auth');
    }

    /**
     * Real-time AJAX search for the public index page.
     */
    public function publicAjaxSearch(\Illuminate\Http\Request $request): JsonResponse
    {
        $term     = trim($request->input('q', ''));
        $category = $request->input('category', '');

        $query = RPublication::published()->with(['user'])->latest('approved_at');

        if ($term !== '') {
            $query->search($term);
        }

        if ($category !== '') {
            $query->where('category', $category);
        }

        $results = $query->limit(8)->get()->map(fn($p) => [
            'id'             => $p->id,
            'title'          => $p->title,
            'abstract'       => \Illuminate\Support\Str::limit($p->abstract, 120),
            'category_label' => $p->category_label,
            'author'         => $p->user->name ?? 'Unknown',
            'date'           => $p->approved_at?->format('M d, Y') ?? 'N/A',
            'url'            => route('research.public.show', $p),
            'cover_image'    => $p->cover_image ? \Illuminate\Support\Facades\Storage::url($p->cover_image) : null,
        ]);

        return response()->json(['success' => true, 'data' => $results]);
    }

    /**
     * Download a private publication file (authenticated users only).
     */
    public function downloadFile(\App\Models\RPublicationFile $file): mixed
    {
        $publication = $file->publication;

        // Author can always download their own files
        // Reviewers and managers can download files under review
        $canAccess = $publication->isAuthor(auth()->id())
            || auth()->user()->can('review publications')
            || auth()->user()->can('view publications');

        abort_unless($canAccess, 403);

        // Use the correct disk based on where the file was stored.
        // Files uploaded via SubmissionService go to 'private'.
        // Files created from the public guest form go to 'public'.
        $diskName = $file->is_public ? 'public' : 'private';
        $disk = \Illuminate\Support\Facades\Storage::disk($diskName);

        if (!$disk->exists($file->file_path)) {
            // Fallback: try the other disk in case the flag is wrong
            $fallbackDisk = $file->is_public ? 'private' : 'public';
            $fallback = \Illuminate\Support\Facades\Storage::disk($fallbackDisk);

            if ($fallback->exists($file->file_path)) {
                $disk = $fallback;
            } else {
                abort(404, 'File not found.');
            }
        }

        // Increment download count
        $file->increment('download_count');

        return $disk->download($file->file_path, $file->original_name);
    }

    /**
     * Search publications (AJAX — authenticated dashboard).
     */
    public function search(Request $request): JsonResponse
    {
        $results = $this->searchService->searchPublications(
            $request->input('q', ''),
            $request->only(['category', 'author_id', 'from_date', 'to_date'])
        );

        return response()->json([
            'success' => true,
            'data' => $results,
        ]);
    }
}
