<?php

namespace App\Http\Controllers;

use App\Enums\CallEvents;
use App\Http\Requests\Call\ListRequest;
use App\Http\Requests\Call\StoreRequest;
use App\Http\Requests\Call\UpdateRequest;
use App\Http\Resources\Call\CallResource;
use app\Http\Traits\ApiResponse;
use App\Models\Call;
use App\Models\CallHistory;
use App\Models\Category;
use App\Models\Event;
use App\Models\User;
use App\Services\Notification\Exceptions\NotificationServerNotRespondingException;
use App\Services\Notification\Exceptions\OperatorNotConnectedException;
use App\Services\Notification\Exceptions\OperatorOfflineException;
use App\Services\Notification\NotificationService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class CallController extends Controller
{
    use ApiResponse;

    /**
     * @throws OperatorNotConnectedException
     * @throws OperatorOfflineException
     * @throws NotificationServerNotRespondingException
     */
    public function store(StoreRequest $request, NotificationService $notificationService): JsonResponse
    {
        try
        {
            $call = DB::transaction(function () use ($request)
            {
                $operator = User::query()->where('telephone_id', '=', $request->extension)->first();

                $call = Call::query()->create([
                    'telephone_id' => $request->extension,
                    'caller_phone_number' => $request->caller_id,
                    'operator_id' => $operator->id,
                    'operator_username' => $operator->username,
                    'operator_full_name' => $operator->full_name
                ]);

                CallHistory::recordHistory($call, CallEvents::CALL_CREATED->value);

                return $call;
            });

            $data = [
                'telephone_id' => $call->telephone_id,
                'phone_number' => $call->caller_phone_number,
                'call_id' => $call->id,
            ];

            $notificationService->deliverDataToNotificationServer($data);

            return $this->successResponse();
        }
        catch (NotificationServerNotRespondingException $exception)
        {
            CallHistory::recordHistory($call, CallEvents::NOTIFICATION_SERVER_NOT_RESPONDING->value);
            throw $exception;
        }
        catch (OperatorOfflineException $exception)
        {
            CallHistory::recordHistory($call, CallEvents::OPERATOR_IS_OFFLINE->value);
            throw $exception;
        }
        catch (OperatorNotConnectedException $exception)
        {
            CallHistory::recordHistory($call, CallEvents::OPERATOR_COULD_NOT_CONNECT->value);
            throw $exception;
        }
    }

    public function update(UpdateRequest $request, Call $call): JsonResponse
    {
        DB::transaction(function () use ($request, $call) {
            $operator = User::query()->where('telephone_id', '=', $call->telephone_id)->first();

            $category = Category::query()->where([
                ['category_id', '=', $request->category_id],
                ['subcategory_id', '=', $request->subcategory_id]
            ])->first();

            $call->update([
                'province_id' => $operator->province_id,
                'province_fa' => $operator->province_fa,
                'operator_id' => $operator->id,
                'operator_username' => $operator->username,
                'operator_full_name' => $operator->full_name,
                'category_id' => $request->category_id,
                'category_name' => $category->category_name,
                'subcategory_id' => $request->subcategory_id,
                'subcategory_name' => $category->subcategory_name,
                'description' => $request->description,
            ]);

            $event_id = CallEvents::OPERATOR_STORED_CALL_DATA->value;

            $event_name = Event::query()->find($event_id)->first()->name;

            CallHistory::query()->create([
                'call_id' => $call->id,
                'telephone_id' => $call->telephone_id,
                'caller_phone_number' => $call->caller_phone_number,
                'event_id' => $event_id,
                'event_name' => $event_name,
            ]);
        });

        return $this->successResponse();
    }

    public function list(ListRequest $request): JsonResponse
    {
        $phone_number = $request->phone_number;
        $size = $request->size ?? config('global_variables.MAX_RECORDS_COUNT');

        $calls_data = Call::query()
            ->when($phone_number, fn($query, $phone_number) => $query->where('phone_number', '=', $phone_number))
            ->orderBy('created_at', 'DESC')
            ->limit($size)
            ->get();

        return $this->successResponse(CallResource::collection($calls_data));
    }

    public function search(Request $request): JsonResponse
    {
        $results = CallHistory::query()
            ->where('caller_phone_number', '=', $request->caller_phone_number)
            ->get();

        return $this->successResponse($results);
    }
}
