<?php

namespace App\Modules\HR\Recruitment\Controllers;

use App\Http\Controllers\Controller;
use App\Modules\HR\Recruitment\Models\RecruitmentOfferLetter;
use App\Modules\HR\Recruitment\Models\RecruitmentOfferLetterAttachment;
use App\Modules\HR\Recruitment\Requests\OfferLetterDecisionRequest;
use App\Modules\HR\Recruitment\Requests\StoreOfferLetterAttachmentRequest;
use App\Modules\HR\Recruitment\Services\RecruitmentOfferLetterAttachmentService;
use App\Modules\HR\Recruitment\Services\RecruitmentOfferLetterExpiryService;
use App\Modules\HR\Recruitment\Services\RecruitmentOfferLetterPdfService;
use App\Modules\HR\Recruitment\Services\RecruitmentOfferLetterStatusHistoryService;
use App\Modules\HR\Recruitment\Services\RecruitmentOfferLetterWorkflowService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\StreamedResponse;

class OfferLetterWorkflowController extends Controller
{
    public function __construct(
        private readonly RecruitmentOfferLetterWorkflowService $workflow,
        private readonly RecruitmentOfferLetterExpiryService $expiry,
        private readonly RecruitmentOfferLetterStatusHistoryService $history,
        private readonly RecruitmentOfferLetterPdfService $pdf,
        private readonly RecruitmentOfferLetterAttachmentService $attachments,
    ) {}

    public function show(RecruitmentOfferLetter $offerLetter): View
    {
        $this->authorize('view', $offerLetter);
        $offer = $this->expiry->expireIfPastDeadline(
            $offerLetter->load([
                'candidate', 'vacancy', 'department', 'position', 'employmentStatus',
                'application', 'attachments',
            ]),
            $this->workflow,
            (int) auth()->id(),
        );

        return view('pages.hr.recruitment.offer-letters.show', [
            'offer' => $offer,
            'timelineSteps' => $this->history->timelineSteps($offer),
        ]);
    }

    public function submit(RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        return $this->run($offerLetter, 'submit', 'submitted');
    }

    public function approve(RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        return $this->run($offerLetter, 'approve', 'approved');
    }

    public function send(RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        $this->authorize('update', $offerLetter);
        $this->workflow->send($offerLetter, (int) auth()->id());
        $this->pdf->generateAndStore($offerLetter->fresh());

        return back()->with('status', __('recruitment.offer_letters.flash.sent'));
    }

    public function resend(RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        return $this->run($offerLetter, 'resend', 'resent');
    }

    public function accept(OfferLetterDecisionRequest $request, RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        $this->authorize('update', $offerLetter);
        $this->workflow->accept($offerLetter, (int) auth()->id(), $request->validated('notes'));

        return back()->with('status', __('recruitment.offer_letters.flash.accepted'));
    }

    public function reject(OfferLetterDecisionRequest $request, RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        $this->authorize('update', $offerLetter);
        $this->workflow->reject($offerLetter, (int) auth()->id(), $request->validated('notes'));

        return back()->with('status', __('recruitment.offer_letters.flash.rejected'));
    }

    public function expire(OfferLetterDecisionRequest $request, RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        $this->authorize('update', $offerLetter);
        $this->workflow->expire($offerLetter, (int) auth()->id(), $request->validated('notes'));

        return back()->with('status', __('recruitment.offer_letters.flash.expired'));
    }

    public function withdraw(OfferLetterDecisionRequest $request, RecruitmentOfferLetter $offerLetter): RedirectResponse
    {
        $this->authorize('update', $offerLetter);
        $this->workflow->withdraw($offerLetter, (int) auth()->id(), $request->validated('notes'));

        return back()->with('status', __('recruitment.offer_letters.flash.withdrawn'));
    }

    public function print(RecruitmentOfferLetter $offerLetter): View
    {
        $this->authorize('view', $offerLetter);

        return view('pages.hr.recruitment.offer-letters.print', [
            'offer' => $offerLetter->load([
                'candidate', 'vacancy', 'department', 'position', 'employmentStatus',
            ]),
        ]);
    }

    public function downloadPdf(RecruitmentOfferLetter $offerLetter): Response
    {
        $this->authorize('view', $offerLetter);
        $binary = $this->pdf->binary($offerLetter);
        $name = $offerLetter->reference_code.'.pdf';

        return response($binary, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'attachment; filename="'.$name.'"',
        ]);
    }

    public function storeAttachment(
        StoreOfferLetterAttachmentRequest $request,
        RecruitmentOfferLetter $offerLetter,
    ): RedirectResponse {
        $this->attachments->store($offerLetter, $request->file('attachment'), (int) auth()->id());

        return back()->with('status', __('recruitment.offer_letters.flash.attachment_uploaded'));
    }

    public function downloadAttachment(RecruitmentOfferLetterAttachment $attachment): StreamedResponse
    {
        $attachment->loadMissing('offerLetter');
        abort_if($attachment->offerLetter === null, 404);
        $this->authorize('view', $attachment->offerLetter);
        abort_unless(Storage::disk('local')->exists($attachment->file_path), 404);

        return Storage::disk('local')->download($attachment->file_path, $attachment->original_name);
    }

    public function destroyAttachment(RecruitmentOfferLetterAttachment $attachment): RedirectResponse
    {
        $attachment->loadMissing('offerLetter');
        abort_if($attachment->offerLetter === null, 404);
        $this->authorize('update', $attachment->offerLetter);
        $this->attachments->destroy($attachment);

        return back()->with('status', __('recruitment.offer_letters.flash.attachment_deleted'));
    }

    private function run(RecruitmentOfferLetter $offer, string $method, string $flash): RedirectResponse
    {
        $this->authorize('update', $offer);
        $this->workflow->{$method}($offer, (int) auth()->id());

        return back()->with('status', __('recruitment.offer_letters.flash.'.$flash));
    }
}
