<?php

namespace App\Http\Controllers\v1\Tenancy\Visit;

use App\Actions\Tenancy\Visit\CreateVisitsMedikAction;
use App\Http\Controllers\Controller;
use App\Http\Requests\Tenancy\Visit\CreateMedikVisitRequest;
use App\Models\Tenancy\Employee;
use App\Models\Tenancy\Procedure;
use App\Models\Tenancy\UserDetails;
use App\Models\Tenancy\Visit;
use App\Models\Tenancy\VisitHistory;
use Illuminate\Http\Response;
use Illuminate\Validation\ValidationException;

class CreateMedikVisitController extends Controller
{
    /**
     * @throws ValidationException
     */
    public function __invoke(CreateMedikVisitRequest $request, CreateVisitsMedikAction $action): Response
    {
        $validatedData = $request->validated();
        $medikProcedureIds = array_column($validatedData['visits'], 'medik_procedure_id');
        $client = UserDetails::byPersonalId($validatedData['client_personal_id'])->first();
        if (! $client) {
            $newClientData = [
                'personal_id' => $validatedData['client_personal_id'],
                'name' => $validatedData['client_firstname'],
                'lastname' => $validatedData['client_lastname'],
                'phone' => $validatedData['client_phone'],
                'create_date' => now()->toDateTimeString(),
                'unique_id' => md5(uniqid().time()),
                'birth_date' => $validatedData['birth_date'],
                'gender' => $validatedData['sex']
            ];

            $client = UserDetails::createClient($newClientData);
        }

        if (isset($validatedData['user'])) {
            $parentsQuery = UserDetails::with('children');
            $existingUsers = [];

            // Query to find matching users
            foreach ($validatedData['user'] as $parentData) {
                $parentsQuery->orWhere(
                    fn($query) => $query
                        ->where('phone', $parentData['phone'])
                        ->where('personal_id', $parentData['personal_id'])
                );
            }

            $parents = $parentsQuery->get();

            foreach ($parents as $parent) {
                $existingUsers[] = [
                    'phone' => $parent->phone,
                    'personal_id' => $parent->personal_id
                ];

                $parent->children()->attach(
                    $client->id,
                    [
                        'parent_name' => $parent->name,
                        'phone' => $parent->phone,
                        'personal_id' => $parent->personal_id
                    ]
                );
            }

            // Find users that were not found in the database
            $notFoundUsers = array_filter($validatedData['user'], function ($user) use ($existingUsers) {
                return !in_array([
                    'phone' => $user['phone'],
                    'personal_id' => $user['personal_id']
                ], $existingUsers);
            });
            foreach ($notFoundUsers as $notFoundUser) {
                $notFoundUser['name'] = $notFoundUser['firstname'];
                $notFoundUser['create_date'] = now()->toDateTimeString();
                $notFoundUser['unique_id'] = md5(uniqid().time());
                unset($notFoundUser['firstname']);
                $createdParent = UserDetails::createClient($notFoundUser);
                $createdParent->children()->attach(
                    $client->id,
                    [
                        'parent_name' => $createdParent->name,
                        'phone' => $createdParent->phone,
                        'personal_id' => $createdParent->personal_id,
                    ]
                );
            }
        }

        $visits = Visit::byClientId($client->id)->orderBy('planned_id', 'DESC')->first();
        $visitsHistory = VisitHistory::byClientId($client->id)->orderBy('planned_id', 'DESC')->first();
        $plannedId = 0;
        if ($visits || $visitsHistory) {
            $plannedId = max($visits->planned_id, $visits->planned_id);
        }

        $specialists = Employee::where('status', 'default')->whereNotNull('doctor_id')
                ->with('doctor')
                ->get();
        $procedures = Procedure::whereIn('medik_id', $medikProcedureIds)->get();
        $data = [];
        foreach ($validatedData['visits'] as $visitData) {
            $procedure = $procedures->where('medik_id', $visitData['medik_procedure_id'])->first();
            if (! $procedure) {
                throw ValidationException::withMessages([
                    'procedures' => 'Medik procedure id doesn\'t exist',
                ]);
            }
            $specialistId = false;

            foreach ($specialists as $specialist) {
                if ($specialist->doctor->personal_id === $visitData['specialist_personal_id']) {
                    $specialistId = $specialist->id;
                }
            }
            if (! $specialistId) {
                throw ValidationException::withMessages([
                    'procedures' => 'Specialist personal id doesn\'t exist',
                ]);
            }
            $data[] = [
                'client_id' => $client->id,
                'is_alien' => $client->is_alien,
                'name' => $client->name,
                'lastname' => $client->lastname,
                'phone' => $client->phone,
                'personal_id' => $client->personal_id,
                'procedure_id' => $procedure->id,
                'date' => $visitData['date'],
                'specialist_id' => $specialistId,
                'planned_id' => $plannedId,
                'x_ray' => in_array($visitData['medik_procedure_id'], config('x-ray.medik_ids')),
            ];
        }

        return $this->ok($action->execute(
            $data,
            $validatedData['paid_amount'],
            $validatedData['send_sms'] ?? false,
            $validatedData['send_email'] ?? false,
            $validatedData['sms_url'] ?? null
        ));
    }
}
