<?php

namespace App\Services;

use App\Enums\LocationState;
use App\Helpers\DateHelper;
use App\Models\Group;
use App\Models\Location;
use App\Models\Procedure;
use App\Models\Process;
use App\Repositories\LocationRepository;
use App\Repositories\ProcessRepository;
use DateTime;
use Exception;

class LocationService
{
    protected ProcedureService $procedureService;
    protected ProcessRepository $processRepository;
    protected LocationRepository $locationRepository;

    public function __construct() {
        $this->procedureService = new ProcedureService();
        $this->locationRepository = new LocationRepository();
        $this->processRepository = new ProcessRepository();
    }

    public function getActualLocation($processId, $groupId, $subgroupId = null)
    {
        return $this->locationRepository->getActualLocation($processId, $groupId, $subgroupId);
    }


    public function createInitialLocations($process, $data, $session)
    {
        $locations = [];

        if (!empty($data['procedure_id']) && $data['procedure_id'] !== 'other') {
            $procedure = Procedure::find($data['procedure_id']);
            $route = $this->procedureService->getOrderedRoutes($procedure);

            if (empty($route)) {
                throw new Exception("No se encontró una ruta definida para este procedimiento.");
            }

            $firstNode = $route[0];

            $locations[] = $this->createLocation(
                $process->id,
                $firstNode->group_id,
                $firstNode->subgroup_id,
                $firstNode->id,
                ($session['role'] !== 'COMUNITY') ? LocationState::DERIVADO : LocationState::PENDIENTE,
                $process->entry_date,
                ($session['role'] !== 'COMUNITY') ? $process->entry_date : null,
                ($session['role'] !== 'COMUNITY') ? $process->entry_date : null,
                $data['comment'] ?? null
            );

            if ($session['role'] !== 'COMUNITY' && count($route) > 1) {
                $secondNode = $route[1]; // Tomar el segundo nodo

                $locations[] = $this->createLocation(
                    $process->id,
                    $secondNode->group_id,
                    $secondNode->subgroup_id,
                    $secondNode->id,
                    LocationState::PENDIENTE,
                    $process->entry_date
                );
            }

            return $locations;
        }

        else {
            
            $mesaPartesGroup = Group::findBy('description', 'MESA DE PARTES');
            if (!$mesaPartesGroup) {
                throw new Exception("No se encontró el grupo 'MESA DE PARTES'.");
            }

            $locations[] = $this->createLocation(
                $process->id,
                $mesaPartesGroup->id,
                null,
                null,
                ($session['role'] === 'COMUNITY') ? LocationState::PENDIENTE : LocationState::RECIBIDO,
                $process->entry_date,
                ($session['role'] !== 'COMUNITY') ? $process->entry_date : null,
                null,
                $data['comment'] ?? null
            );

            return $locations;
        }
    }



    // public function createInitialLocations($process, $data, $session)
    // {
    //     $locations = [];

    //     $procedure = Procedure::find($data['procedure_id']);
    //     $route = $this->procedureService->getOrderedRoutes($procedure);

    //     if (empty($route)) {
    //         throw new Exception("No se encontró una ruta definida para este procedimiento.");
    //     }

    //     $firstNode = $route[0];

    //     $locations[] = $this->createLocation(
    //         $process->id, 
    //         $firstNode->group_id, 
    //         $firstNode->subgroup_id,
    //         $firstNode->id, 
    //         ($session['role'] !== 'COMUNITY') ? LocationState::DERIVADO : LocationState::PENDIENTE,
    //         $process->entry_date,
    //         ($session['role'] !== 'COMUNITY') ? $process->entry_date : null,
    //         ($session['role'] !== 'COMUNITY') ? $process->entry_date : null,
    //         $data['comment'] ?? null
    //     );

    //     if ($session['role'] !== 'COMUNITY' && count($route) > 1) {
    //         $secondNode = $route[1]; // Tomar el segundo nodo

    //         $locations[] = $this->createLocation(
    //             $process->id,
    //             $secondNode->group_id,
    //             $secondNode->subgroup_id,
    //             $secondNode->id,
    //             LocationState::PENDIENTE,
    //             $process->entry_date
    //         );
    //     }

    //     return $locations;
    // }

    public function createLocation($processId, $groupId, $subgroupId, $procedure_route_id, $state, $derivedDate, $receiptDate = null, $attended_date = null, $comment = null)
    {
        $location = new Location();
        $location->process_id = $processId;
        $location->group_id = $groupId;
        $location->subgroup_id = $subgroupId;
        $location->procedure_route_id = $procedure_route_id;
        $location->state = $state;
        $location->derived_date = DateHelper::adjustToBusinessDate($derivedDate)->format('Y-m-d H:i:s');
        $location->receipt_date = $receiptDate;
        $location->attended_date = $attended_date;
        $location->comment = $comment;
        $location->deleted_at = null;
        $location->save(); 

        return $location;
    }

    public function acceptLocation($location): bool
    {
        $adjustedDate = DateHelper::adjustToBusinessDate(new DateTime())->format('Y-m-d H:i:s');

        $process = Process::find($location->process_id);

        $updated = $this->locationRepository->updateAsReceived(
            $location->id,
            LocationState::RECIBIDO,
            $adjustedDate
        );

        // if ($updated) {

        //     if ($this->isFirstNode($location, $process)) {
        //         $nextNode = $this->getNextRouteNode($location);

        //         $newLocation = $this->createLocation(
        //             $location->process_id,
        //             $nextNode->group_id,
        //             $nextNode->subgroup_id ?: null,
        //             $nextNode->id,
        //             LocationState::PENDIENTE,
        //             date('Y-m-d H:i:s')
        //         );

        //         $this->processRepository->updateLastLocation($process->id, $newLocation->id);

        //         NotificationService::createNotification(
        //             $process->id,
        //             "El trámite {$process->num_exped} ha sido derivado a su equipo.",
        //             null,
        //             $nextNode->group_id,
        //             $nextNode->subgroup_id
        //         );
        //     }
        // }

        return $updated;
    }

    // public function acceptLocation($location): bool
    // {
    //     $adjustedDate = DateHelper::adjustToBusinessDate(new DateTime())->format('Y-m-d H:i:s');

    //     $process = Process::find($location->process_id);

    //     if ($this->isFirstNode($location, $process)) {
    //         $updated = $this->locationRepository->updateAsDerived(
    //             $location->id,
    //             LocationState::DERIVADO,
    //             $adjustedDate,
    //             $adjustedDate
    //         );
    //     } else {
    //         $updated = $this->locationRepository->updateAsReceived(
    //             $location->id,
    //             LocationState::RECIBIDO,
    //             $adjustedDate
    //         );
    //     }

    //     if ($updated) {

    //         if ($this->isFirstNode($location, $process)) {
    //             $nextNode = $this->getNextRouteNode($location);

    //             $newLocation = $this->createLocation(
    //                 $location->process_id,
    //                 $nextNode->group_id,
    //                 $nextNode->subgroup_id ?: null,
    //                 $nextNode->id,
    //                 LocationState::PENDIENTE,
    //                 date('Y-m-d H:i:s')
    //             );

    //             $this->processRepository->updateLastLocation($process->id, $newLocation->id);

    //             NotificationService::createNotification(
    //                 $process->id,
    //                 "El trámite {$process->num_exped} ha sido derivado a su equipo.",
    //                 null,
    //                 $nextNode->group_id,
    //                 $nextNode->subgroup_id
    //             );
    //         }
    //     }

    //     return $updated;
    // }

    public function acceptAllLocationsByGroup(int $groupId, ?int $subgroupId = null): bool
    {
        $locations = $this->locationRepository->findPendingByGroup($groupId, $subgroupId);

        if (empty($locations)) {
            return false;
        }

        $allUpdated = true;

        foreach ($locations as $location) {
            $success = $this->acceptLocation($location);
            if (!$success) {
                $allUpdated = false;
            }
        }

        // Notificaciones generales: marcar como leídas las pendientes del grupo
        NotificationService::markNotificationsAsReadByGroup($groupId, $subgroupId);

        return $allUpdated;
    }


    public function getNextRouteNode($location)
    {
        return $this->locationRepository->getNextRouteNode($location);
    }

    public function isFirstNode($location, $process): bool
    {
        $firstStep = $this->procedureService->getFirstNode($process->procedure_id);
        return $firstStep && $firstStep->id === $location->procedure_route_id;
    }

    public function isFinalNode($location, $process): bool
    {
        $finalNode = $this->procedureService->getFinalNode($process->procedure_id);
        return $finalNode && $finalNode->id === $location->procedure_route_id;
    }

    public function getLocationsWithRelationsByProcessId(int $processId)
    {
        return $this->locationRepository->getLocationsWithRelationsByProcessId($processId);
    }

    public function getFirstLocationByProcessId(int $processId)
    {
        return $this->locationRepository->getFirstLocationByProcessId($processId);
    }
}
