<?php

namespace Modules\MembershipApplication\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Services\DocumentService;
use App\Services\LetterService;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Modules\MembershipApplication\Entities\MembershipApplication;
use Modules\MembershipApplication\Enums\ApplicationStatus;
use Modules\MembershipApplication\Enums\BoardDecision;
use Modules\MembershipApplication\Enums\BoardResult;
use Modules\MembershipApplication\Enums\ManagementDecision;
use Modules\MembershipApplication\Http\Requests\AssignReferencesRequest;
use Modules\MembershipApplication\Http\Requests\BatchCompleteRequest;
use Modules\MembershipApplication\Http\Requests\BoardReviewRequest;
use Modules\MembershipApplication\Http\Requests\ManagementReviewRequest;
use Modules\MembershipApplication\Http\Requests\UpdateMembershipApplicationRequest;
use Modules\MembershipApplication\Http\Requests\UploadMembershipApplicationDocumentRequest;
use Modules\MembershipApplication\Services\MembershipApplicationService;
use Modules\MembershipApplication\Transformers\MembershipApplicationListResource;
use Modules\MembershipApplication\Transformers\MembershipApplicationResource;
use Symfony\Component\HttpFoundation\StreamedResponse;

class MembershipApplicationController extends Controller
{
    use AuthorizesRequests;

    public function __construct(
        protected MembershipApplicationService $membershipApplicationService,
        protected DocumentService $documentService,
        protected LetterService $letterService,
    ) {}

    public function index(Request $request): JsonResponse
    {
        $this->authorize('viewAny', MembershipApplication::class);

        $perPage = min((int) $request->get('per_page', 10), 100);
        $search = (string) ($request->get('search', '') ?? '');
        $status = $request->get('status');
        $sortBy = (string) ($request->get('sort_by', 'submitted_at') ?? 'submitted_at');
        $sortOrder = (string) ($request->get('sort_order', 'desc') ?? 'desc');

        $applications = $this->membershipApplicationService->getPaginatedList(
            $perPage,
            $search,
            $status,
            $sortBy,
            $sortOrder
        );

        return response()->json([
            'success' => true,
            'data' => MembershipApplicationListResource::collection($applications->items()),
            'pagination' => [
                'current_page' => $applications->currentPage(),
                'per_page' => $applications->perPage(),
                'total' => $applications->total(),
                'last_page' => $applications->lastPage(),
                'from' => $applications->firstItem(),
                'to' => $applications->lastItem(),
                'has_more_pages' => $applications->hasMorePages(),
            ],
        ]);
    }

    public function show(MembershipApplication $membershipApplication): JsonResponse
    {
        $this->authorize('view', $membershipApplication);

        $application = $this->membershipApplicationService->getByIdWithRelations($membershipApplication->id);

        if (! $application) {
            return response()->json([
                'success' => false,
                'message' => 'Permohonan tidak dijumpai.',
            ], 404);
        }

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

    public function update(UpdateMembershipApplicationRequest $request, MembershipApplication $membershipApplication): JsonResponse
    {
        $this->authorize('update', $membershipApplication);

        $application = $this->membershipApplicationService->update(
            $membershipApplication,
            $request->validated(),
        );

        return response()->json([
            'success' => true,
            'message' => 'Permohonan keahlian berjaya dikemaskini.',
            'data' => new MembershipApplicationResource($application),
        ]);
    }

    public function uploadDocument(UploadMembershipApplicationDocumentRequest $request, MembershipApplication $membershipApplication): JsonResponse
    {
        $this->authorize('update', $membershipApplication);

        $application = $this->membershipApplicationService->uploadDocument(
            $membershipApplication,
            $request->validated('type'),
            $request->file('file'),
        );

        return response()->json([
            'success' => true,
            'message' => 'Dokumen berjaya dimuat naik.',
            'data' => new MembershipApplicationResource($application),
        ]);
    }

    public function managementReview(ManagementReviewRequest $request, MembershipApplication $membershipApplication): JsonResponse {
        $this->authorize('managementReview', $membershipApplication);

        $application = $this->membershipApplicationService->managementReview(
            $membershipApplication,
            ManagementDecision::from($request->validated('decision')),
            $request->validated('remarks'),
            $request->user()
        );

        $message = $application->status === ApplicationStatus::PendingBoard
            ? 'Permohonan diluluskan dan dihantar ke lembaga.'
            : 'Permohonan ditolak.';

        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => new MembershipApplicationResource($application),
        ]);
    }

    public function boardReview(BoardReviewRequest $request, MembershipApplication $membershipApplication): JsonResponse {
        $this->authorize('boardReview', $membershipApplication);

        $application = $this->membershipApplicationService->boardReview(
            $membershipApplication,
            BoardDecision::from($request->validated('decision')),
            $request->validated('remarks'),
            $request->user()
        );

        $message = $application->board_result === BoardResult::Pass->value
            ? 'Permohonan lulus semakan lembaga.'
            : 'Permohonan gagal semakan lembaga.';

        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => new MembershipApplicationResource($application),
        ]);
    }

    public function assignReferences(AssignReferencesRequest $request, MembershipApplication $membershipApplication): JsonResponse {
        $this->authorize('assignReferences', $membershipApplication);

        $application = $this->membershipApplicationService->assignReferences(
            $membershipApplication,
            $request->validated(),
            $request->user()
        );

        return response()->json([
            'success' => true,
            'message' => 'Pencadang dan penyokong berjaya dikemaskini.',
            'data' => new MembershipApplicationResource($application),
        ]);
    }

    public function complete(Request $request, MembershipApplication $membershipApplication): JsonResponse
    {
        $this->authorize('complete', $membershipApplication);

        $application = $this->membershipApplicationService->complete(
            $membershipApplication,
            $request->user()
        );

        $message = $application->board_result === BoardResult::Pass->value
            ? 'Permohonan selesai. Akaun ahli telah dicipta dan e-mel dihantar.'
            : 'Permohonan selesai. E-mel keputusan dihantar.';

        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => new MembershipApplicationResource($application),
        ]);
    }

    public function batchComplete(BatchCompleteRequest $request): JsonResponse
    {
        $this->authorize('completeBatch', MembershipApplication::class);

        $result = $this->membershipApplicationService->completeBatch(
            $request->validated('application_ids'),
            $request->user()
        );

        $succeededCount = count($result['succeeded']);
        $failedCount = count($result['failed']);

        if ($succeededCount === 0) {
            return response()->json([
                'success' => false,
                'message' => 'Tiada permohonan berjaya diselesaikan.',
                'data' => [
                    'succeeded' => [],
                    'failed' => $result['failed'],
                ],
            ], 422);
        }

        $message = $failedCount > 0
            ? "{$succeededCount} permohonan berjaya, {$failedCount} gagal."
            : "{$succeededCount} permohonan berjaya diselesaikan.";

        return response()->json([
            'success' => true,
            'message' => $message,
            'data' => [
                'succeeded' => MembershipApplicationResource::collection($result['succeeded']),
                'failed' => $result['failed'],
            ],
        ]);
    }

    public function downloadDocument(MembershipApplication $membershipApplication, string $documentId): StreamedResponse {
        $this->authorize('view', $membershipApplication);

        $document = $membershipApplication->documents()->findOrFail($documentId);

        return $this->documentService->downloadDocument($document->id);
    }

    public function approvedLetter(Request $request, MembershipApplication $membershipApplication): Response
    {
        $this->authorize('view', $membershipApplication);

        $application = $this->membershipApplicationService->getByIdWithRelations($membershipApplication->id);

        if (! $application) {
            abort(404, 'Permohonan tidak dijumpai.');
        }

        $view = 'membershipapplication::pdf.approved-letter';
        $data = ['application' => $application];
        $format = $request->query('format', 'html');
        $filename = 'surat-kelulusan-'.$application->application_number.'.pdf';

        if ($format === 'pdf') {
            return $this->letterService->pdfResponse($view, $data, $filename);
        }

        return $this->letterService->htmlResponse($view, $data);
    }
}
