<?php

namespace App\Repositories\Admin;

use Exception;
use Throwable;
use App\Models\User;
use App\Models\Announcement;
use Illuminate\Http\Request;
use App\Services\ImageService;
use App\Enums\NotificationType;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Repositories\General\NotificationRepository;

class AnnouncementRepository
{
    protected $imageService;
    protected $notificationRepository;

    public function __construct(ImageService $imageService, NotificationRepository $notificationRepository)
    {
        $this->imageService = $imageService;
        $this->notificationRepository = $notificationRepository;
    }

    public function getAll()
    {
        $announcements = Announcement::with([
            'user',
            'image',
        ])
            ->filter(request([
                'search',
            ]))
            ->latest('created_at')
            ->paginate(config('pagination.admin'))
            ->withQueryString();

        return compact('announcements');
    }

    public function getTrash()
    {
        $announcements = Announcement::with([
            'user',
            'image',
        ])
            ->onlyTrashed()
            ->filter(request([
                'search',
            ]))
            ->latest('created_at')
            ->paginate(config('pagination.admin'))
            ->withQueryString();

        return compact('announcements');
    }

    public function show($id)
    {
        $announcement = Announcement::with([
            'user',
            'image',
        ])
            ->withTrashed()
            ->find($id);

        return compact('announcement');
    }

    public function save(Request $request)
    {
        $loginUser = auth()->user();
        try {
            DB::beginTransaction();

            $announcement = Announcement::updateOrCreate(
                ['id' => $request->id],
                [
                    'user_id' => $loginUser->id,
                    'title' => $request->title,
                    'description' => $request->description,
                    'link' => $request->link,
                    'start_time' => $request->start_time,
                    'end_time' => $request->end_time,
                ],
            );

            if ($request->hasFile('image')) {
                $oldImage = $announcement->image;
                if ($oldImage) {
                    $this->imageService->delete($oldImage->id, Announcement::class);
                }
                $image = $this->imageService->upload($request->file('image'), Announcement::class);
                $announcement->image()->save($image);
            }

            if ($request->id == null) {
                $users = User::user()->get();
                foreach ($users as $user) {
                    $this->notificationRepository->add(
                        userId: $user->id,
                        content: 'Admin has made an announcement.',
                        imageUrl: $announcement->image?->url,
                        type: NotificationType::ADMIN->value,
                        redirectLink: route('announcement.show', $announcement->id),
                    );
                }
            }

            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();

            Log::error(__CLASS__ . '::' . __FUNCTION__ . '[line: ' . __LINE__ . ']Message: ' . $e->getMessage());

            throw new Exception('Announcement saved failed.');
        }
    }

    public function destroy(Announcement $announcement)
    {
        try {
            DB::beginTransaction();

            $announcement->delete();

            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();

            Log::error(__CLASS__ . '::' . __FUNCTION__ . '[line: ' . __LINE__ . ']Message: ' . $e->getMessage());

            throw new Exception('Announcement deleted failed.');
        }
    }

    public function restore($id)
    {
        try {
            DB::beginTransaction();

            $announcement = Announcement::onlyTrashed()->findOrFail($id);

            $announcement->restore();

            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();

            Log::error(__CLASS__ . '::' . __FUNCTION__ . '[line: ' . __LINE__ . ']Message: ' . $e->getMessage());

            throw new Exception('Announcement restored failed.');
        }
    }
}
