<?php

namespace App\Controllers;

use App\Models\Area;
use App\Models\Modality;
use App\Models\Procedure;
use App\Models\ProcedureRoute;
use App\Services\AreaService;
use App\Services\ProcedureService;

class ProcedureController extends BaseController
{
    protected ProcedureService $procedureService;
    protected AreaService $areaService;

    public function __construct() {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        $this->procedureService = new ProcedureService();
        $this->areaService = new AreaService();
    }

    public function index()
    {
        $procedures = Procedure::getActives();
        $this->render('procedures/procedures-index', ['procedures' => $procedures]);
    }

    public function create()
    {
        $modalities = Modality::getActives();
        $this->render('procedures/procedures-create', ['modalities' => $modalities]); 
    }

    public function edit($id)
    {
        $procedure = Procedure::find($id);
        if (!$procedure) {
            $_SESSION['message'] = "Error: Procedimiento no encontrado.";
            $_SESSION['message_type'] = "danger";
            header("Location: " . BASE_HEADER . "procedures");
            exit;
        }
        $modalities = Modality::getActives();
        $this->render('procedures/procedures-edit', ['procedure' => $procedure, 'modalities' => $modalities]);
    }

    public function store()
    {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $description = $_POST['description'] ?? '';
            $time = $_POST['time'] ?? 1;
            $modality_id = $_POST['modality_id'] ?? '';
            $correction_days = $_POST['correction_days'] ?? 2;
    
            if (empty($time) || empty($description) || empty($modality_id) || empty($correction_days)) {
                $_SESSION['message'] = "Error: Todos los campos son obligatorios.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures/create");
                exit;
            }

            $modality = Modality::find($modality_id);

            if (!$modality) {
                $_SESSION['message'] = "Modalidad seleccionada no válida.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures/create");
                exit;
            }

            $procedure = new Procedure();
            $procedure->description = $description;
            $procedure->group_id = $_POST['group_id'] ?? null;
            $procedure->subgroup_id = $_POST['subgroup_id'] ?? null;
            $procedure->time = $time;
            $procedure->modality_id = $modality_id;
            $procedure->correction_days = $correction_days;
            $procedure->save();
    
            $_SESSION['message'] = "Procedimiento creado exitosamente!";
            $_SESSION['message_type'] = "success";
            header("Location: " . BASE_HEADER . "procedures-route/$procedure->id");
            exit;
        }
    }

    public function update($id)
    {
        if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['_method']) && $_POST['_method'] === 'PUT') {
            $procedure = Procedure::find($id);
    
            if (!$procedure) {
                $_SESSION['message'] = "Error: Procedimiento no encontrado.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures");
                exit;
            }
    
            $procedure->description = $_POST['description'] ?? '';
            $procedure->group_id = $_POST['group_id'] ?? null;
            $procedure->subgroup_id = $_POST['subgroup_id'] ?? null;
            $procedure->time = $_POST['time'] ?? 1;
            $procedure->modality_id = $_POST['modality_id'] ?? null;
            $procedure->correction_days = $_POST['correction_days'] ?? 2;
            $procedure->active = $_POST['active'] ?? 0;
    
            if (empty($procedure->description) || empty($procedure->time) || empty($procedure->modality_id)) {
                $_SESSION['message'] = "Error: Todos los campos son obligatorios.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures/$id/edit");
                exit;
            }

            $modality = Modality::find($procedure->modality_id);

            if (!$modality) {
                $_SESSION['message'] = "Modalidad seleccionada no válida.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures/$id/edit");
                exit;
            }
    
            $procedure->save();
            $_SESSION['message'] = "Procedimiento actualizado exitosamente!";
            $_SESSION['message_type'] = "success";
    
            header("Location: " . BASE_HEADER . "procedures");
            exit;
        }
        die("Error: Método no permitido.");
    }

    public function delete($id)
    {
        if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['_method']) && $_POST['_method'] === 'DELETE') {
            $procedure = Procedure::find($id);
            
            if (!$procedure) {
                $_SESSION['message'] = "Error: No se pudo eliminar el procedimiento.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures");
                exit;
            }

            $procedure->delete($procedure->id);
            $_SESSION['message'] = "¡Procedimiento eliminado exitosamente!";
            $_SESSION['message_type'] = "success";
            header("Location: " . BASE_HEADER . "procedures");
            exit;
        }
        die("Error: Método no permitido.");
    }

    public function showRoute($id)
    {
        $procedure = Procedure::find($id);
        if (!$procedure) {
            $_SESSION['message'] = "Error: Procedimiento no encontrado.";
            $_SESSION['message_type'] = "danger";
            header("Location: " . BASE_HEADER . "procedures");
            exit;
        }

        $areas = $this->areaService->getAreasWithRelations();
        $routes = $this->procedureService->getOrderedRoutes($procedure);
        $this->render('procedures/procedures-route', ['procedure' => $procedure, 'areas' => $areas, 'routes' => $routes]);
    }

    public function storeStep($id)
    {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $group_id = $_POST['group_id'] ?? null;
            $subgroup_id = !empty($_POST['subgroup_id']) ? $_POST['subgroup_id'] : null;
            $previous_step_id = ($_POST['previous_step_id'] !== "") ? $_POST['previous_step_id'] : null;

            $procedure = Procedure::find($id);
            if (!$procedure) {
                $_SESSION['message'] = "Error: Procedimiento no encontrado.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures");
                exit;
            }

            if (!$group_id) {
                $_SESSION['message'] = "Error: Debe seleccionar un grupo.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures-route/$procedure->id");
                exit;
            }

            $previousStep = $previous_step_id ? ProcedureRoute::find($previous_step_id) : null;

            if ($previous_step_id && !$previousStep) {
                $_SESSION['message'] = "Error: El paso anterior seleccionado no existe.";
                $_SESSION['message_type'] = "danger";
                header("Location: " . BASE_HEADER . "procedures-route/$procedure->id");
                exit;
            }

            $nextStep = $previousStep ? ProcedureRoute::findBy('previous_step_id', $previous_step_id) : null;

            $newStep = new ProcedureRoute([
                'procedure_id' => $procedure->id,
                'group_id' => $group_id,
                'subgroup_id' => $subgroup_id,
                'previous_step_id' => $previous_step_id,
                'next_step_id' => $nextStep ? $nextStep->id : null
            ]);

            $newStep->save();

            if ($previousStep) {
                $previousStep->next_step_id = $newStep->id;
                $previousStep->save();
            }

            if ($nextStep) {
                $nextStep->previous_step_id = $newStep->id;
                $nextStep->save();
            }

            if (!$previous_step_id) {
                $oldFirstStep = ProcedureRoute::findByMultiple([
                    'procedure_id' => $procedure->id,
                    'previous_step_id' => null,
                    'id' => ['!=', $newStep->id]
                ]);

                if ($oldFirstStep && $oldFirstStep->id !== $newStep->id) {
                    $oldFirstStep->previous_step_id = $newStep->id;
                    $oldFirstStep->save();

                    $newStep->next_step_id = $oldFirstStep->id;
                }

                $newStep->previous_step_id = null;
                $newStep->save();
            }

            $_SESSION['message'] = "Nodo agregado correctamente!";
            $_SESSION['message_type'] = "success";
            header("Location: " . BASE_HEADER . "procedures-route/$procedure->id");
            exit;
        }
    }



    public function editStep($id)
    {
        $route = ProcedureRoute::find($id);
        if (!$route) {
            $_SESSION['message'] = "Error: Nodo no encontrado.";
            $_SESSION['message_type'] = "danger";
            header("Location: " . BASE_HEADER . "procedures");
            exit;
        }

        $areas = $this->areaService->getAreasWithRelations();

        $this->render('procedures/procedures-route-edit', ['areas' => $areas, 'route' => $route]);
    }

    public function updateStep($id)
    {
        $route = ProcedureRoute::find($id);
        if (!$route) {
            $_SESSION['message'] = "Error: Nodo no encontrado.";
            $_SESSION['message_type'] = "danger";
            header("Location: " . BASE_HEADER . "procedures");
            exit;
        }

        $group_id = $_POST['group_id'] ?? null;
        $subgroup_id = !empty($_POST['subgroup_id']) ? $_POST['subgroup_id'] : null;

        if (!$group_id) {
            $_SESSION['error'] = "El grupo es obligatorio.";
            $_SESSION['message_type'] = "danger";
            header("Location: " . BASE_HEADER . "procedures-route/$id/edit");
            exit;
        }

        $route->group_id = $group_id;
        $route->subgroup_id = !empty($subgroup_id) ? $subgroup_id : null;
        $route->save();

        $_SESSION['message'] = "Nodo actualizado correctamente!";
        $_SESSION['message_type'] = "success";
        header("Location: " . BASE_HEADER . "procedures-route/$route->procedure_id");
        exit;
    }

    public function deleteStep($id)
    {
        $route = ProcedureRoute::find($id);
        if (!$route) {
            $_SESSION['message'] = "Error: Nodo no encontrado.";
            $_SESSION['message_type'] = "danger";
            header("Location: " . BASE_HEADER . "procedures");
            exit;
        }

        $previousStep = ProcedureRoute::findBy('next_step_id', $route->id);
        $nextStep = ProcedureRoute::findBy('previous_step_id', $route->id);

        if (!$nextStep) {
            if ($previousStep) {
                $previousStep->next_step_id = NULL;
                $previousStep->save();
            }
            $route->delete($route->id);
        } 
        else {
            if ($previousStep) {
                $previousStep->next_step_id = $route->next_step_id;
                $previousStep->save();
            }

            if ($nextStep) {
                $nextStep->previous_step_id = $route->previous_step_id;
                $nextStep->save();
            }

            $route->delete($route->id);
        }

        if (!$previousStep && $nextStep) {
            $nextStep->previous_step_id = NULL;
            $nextStep->save();
        }

        $_SESSION['message'] = "Nodo eliminado correctamente.";
        $_SESSION['message_type'] = "success";
        header("Location: " . BASE_HEADER . "procedures-route/$route->procedure_id");
        exit;
    }

    public function getProcedureDetails()
    {
        if (!isset($_GET['procedure_id'])) {
            echo json_encode(['error' => 'ID no proporcionado']);
            return;
        }

        $procedureId = $_GET['procedure_id'];
        $procedure = Procedure::find($procedureId);

        if (!$procedure) {
            echo json_encode(['error' => 'Procedimiento no encontrado']);
            return;
        }

        $response = [
            'id' => $procedure->id,
            'description' => $procedure->description,
            'area' => $procedure->area() ? ['id' => $procedure->area()->id, 'description' => $procedure->area()->description] : null,
            'groupType' => $procedure->groupType() ? ['id' => $procedure->groupType()->id, 'description' => $procedure->groupType()->description] : null,
            'group' => $procedure->group() ? ['id' => $procedure->group()->id, 'description' => $procedure->group()->description] : null,
            'subgroup' => $procedure->subgroup() ? ['id' => $procedure->subgroup()->id, 'description' => $procedure->subgroup()->description] : null,
        ];

        echo json_encode($response);
    }


}