<?php

namespace App\Http\Controllers\GeneralNotifications;

use Illuminate\Http\Request;
use Yajra\DataTables\DataTables;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Jobs\SendPushViaFirebaseJob;
use App\Models\GeneralNotifications;
use App\Services\DataTableActionLinksService;
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Routing\Controllers\HasMiddleware;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class NotificationController extends Controller implements HasMiddleware
{
    private string $notFoundMessage = 'Notification not found.';

    /**
     * Get the middleware for the controller.
     *
     * @return array
     */
    public static function middleware(): array
    {
        return [
            new Middleware('permission:notification.view', only: ['index', 'dataTable', 'show']),
            new Middleware('permission:notification.add', only: ['create', 'store']),
            new Middleware('permission:notification.delete', only: ['destroy']),
        ];
    }

    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        return view('notifications.index');
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        return view('notifications.modals.edit');
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'title' => 'required|string|max:250',
            'notification' => 'required|string|max:10000',
        ]);

        try {
            DB::beginTransaction();

            GeneralNotifications::create([
                'title' => $request->input('title'),
                'message' => $request->input('notification'),
                'updated_at' => null,
            ]);

            DB::commit();

            return $this->jsonResponse('Notification created successfully.');
        } catch (\Exception $exception) {
            DB::rollBack();
            return $this->jsonResponse($exception->getMessage(), $exception->getCode());
        }
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $notification = GeneralNotifications::whereUuid($id)->first();
        if (empty($notification)) throw new NotFoundHttpException($this->notFoundMessage);
        return view('notifications.modals.show', compact('notification'));
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {
        try {
            $notification = GeneralNotifications::whereUuid($id)->first();
            if (empty($notification)) throw new NotFoundHttpException($this->notFoundMessage);

            return view('notifications.modals.edit', compact('notification'));
        } catch (\Exception $exception) {
            return $this->jsonResponse($exception->getMessage(), $exception->getCode());
        }
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id): JsonResponse
    {
        $request->validate([
            'title' => 'required|string|max:250',
            'notification' => 'required|string|max:10000',
        ]);

        try {
            $notification = GeneralNotifications::whereUuid($id)->first();
            if (empty($notification)) throw new NotFoundHttpException($this->notFoundMessage);

            DB::beginTransaction();

            $notification->update([
                'title' => $request->input('title'),
                'message' => $request->input('notification'),
                'updated_at' => now(),
            ]);

            DB::commit();

            return $this->jsonResponse('Notification updated successfully.');
        } catch (\Exception $exception) {
            DB::rollBack();
            return $this->jsonResponse($exception->getMessage(), $exception->getCode());
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id): JsonResponse
    {
        try {
            $notification = GeneralNotifications::whereUuid($id)->first();
            if (empty($notification)) throw new NotFoundHttpException($this->notFoundMessage);

            DB::beginTransaction();

            $notification->delete();

            DB::commit();

            return $this->jsonResponse('Notification deleted successfully.');
        } catch (\Exception $exception) {
            DB::rollBack();
            return $this->jsonResponse($exception->getMessage(), $exception->getCode());
        }
    }

    /**
     * Send notification the specified resource from storage.
     */
    public function send(string $id): JsonResponse
    {
        try {
            $notification = GeneralNotifications::whereUuid($id)->first();
            if (empty($notification)) throw new NotFoundHttpException($this->notFoundMessage);

            $notificationData = [
                'title'   => $notification->title,
                'body'    => $notification->message,
                'payload' => ['redirect_url' => ''],
            ];

            SendPushViaFirebaseJob::dispatch($notificationData);

            return $this->jsonResponse('Notification sent successfully to users.');
        } catch (\Exception $exception) {
            DB::rollBack();
            return $this->jsonResponse($exception->getMessage(), $exception->getCode());
        }
    }

    /**
     * Return the listing of the resource.
     */
    public function dataTable(Request $request): JsonResponse
    {
        $notifications = GeneralNotifications::latest();

        $dt = DataTables::of($notifications);

        $dt->filter(function ($query) use ($request) {
            if (empty($request->input('search'))) return;

            $search = trim($request->input('search')['value']);
            $keywords = explode(' ', $search);

            $query->where(function ($query) use ($keywords) {
                foreach ($keywords as $word) {
                    $query->where('message', 'like', "%$word%");
                }
            });
        });

        $dt->addColumn('title', function ($record) {
            return canEmpty(addEllipsis(strip_tags($record->title), 80));
        });

        $dt->addColumn('notification', function ($record) {
            return canEmpty(addEllipsis(strip_tags($record->message), 80));
        });

        $dt->addColumn('created', function ($record) {
            return $record->createdAt();
        });

        $dt->addColumn('updated', function ($record) {
            return $record->updatedAt();
        });

        $dt->addColumn('actions', function ($record) {
            $links = [
                ['action' => 'update'],
                ['action' => 'view'],
                [
                    'action' => 'custom',
                    'shouldRender' => auth()->user()->can('notification.send'),
                    'url' => route('notifications.send', $record->uuid),
                    'attributes' => 'confirm-btn data-method="post" data-datatable="#users-dt" data-message="Do you really want to send this notification?" data-title="Send Notification to Users"',
                    'icon' => 'send',
                    'buttonText' => 'Send Notification',
                    'syncResponse' => true,
                ],
                ['action' => 'delete'],
            ];
            return (new DataTableActionLinksService(
                model: $record,
                routeNamespace: 'notifications',
                permissionNamespace: 'notification',
                datatableId: '#notifications-dt',
            ))->byArray($links);
        });

        $dt->addIndexColumn();

        $dt->rawColumns(['title', 'notification', 'created', 'updated', 'actions']);

        return $dt->make(true);
    }
}
