<?php

namespace App\Controllers\Produccion;

use App\Controllers\BaseController;
use App\Models\OrdenTrabajo\OrdenTrabajoModel;
use App\Models\OrdenTrabajo\OrdenTrabajoTarea;
use App\Models\OrdenTrabajo\OrdenTrabajoUser;
use App\Models\Presupuestos\PresupuestoModel;
use App\Models\Usuarios\UserModel;
use App\Services\ProductionService;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\I18n\Time;
use CodeIgniter\Validation\Validation;
use Config\LogoImpresion;
use Exception;
use Hermawan\DataTables\DataTable;
use Psr\Log\LoggerInterface;

class Ordentrabajo extends BaseController
{
    protected $format = 'json';
    protected array $viewData = [];
    protected ProductionService $produccionService;
    protected OrdenTrabajoModel $otModel;
    protected OrdenTrabajoUser $otUserModel;
    protected OrdenTrabajoTarea $otTarea;
    protected UserModel $userModel;
    protected Validation $validation;
    protected static $viewPath = 'themes/vuexy/form/produccion/';
    protected static $controllerSlug = "orden-trabajo";
    protected $indexRoute = 'viewOrdenTrabajoList';
    protected $indexRoutePlanning = 'ot/viewPlanningRotativa';
    protected $editRoute = 'viewOrdenTrabajoEdit';


    public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
    {
        $this->otModel = model(OrdenTrabajoModel::class);
        $this->userModel = model(UserModel::class);
        $this->produccionService = new ProductionService();
        $this->otTarea = model(OrdenTrabajoTarea::class);
        $this->validation = service("validation");
        helper("time");
        parent::initController($request, $response, $logger);
    }

    public function index()
    {
        // Breadcrumbs
        $this->viewData['breadcrumb'] = [
            ['title' => lang("Produccion.ot"), 'route' => "javascript:void(0);", 'active' => false],
            ['title' => lang("Produccion.ots"), 'route' => site_url('produccion/ordentrabajo'), 'active' => true]
        ];
        return view(static::$viewPath . $this->indexRoute, $this->viewData);
    }
    public function index_planning_rotativa()
    {
        // Breadcrumbs
        $this->viewData['breadcrumb'] = [
            ['title' => lang("Produccion.ots"), 'route' => "javascript:void(0);", 'active' => false],
            ['title' => lang("Produccion.ots"), 'route' => site_url('produccion/ordentrabajo/planning/rotativa'), 'active' => true]
        ];
        return view(static::$viewPath . $this->indexRoutePlanning, $this->viewData);
    }


    public function get_orden_trabajo_summary($orden_trabajo_id)
    {
        try {
            //code...
            $summary = $this->produccionService->init($orden_trabajo_id)->getSummary();
            return $this->response->setJSON($summary);
        } catch (\Throwable $th) {
            return $this->response->setStatusCode(500)->setJSON(["message" => $th->getMessage(), "error" => $th]);
        }
    }
    public function add() {}

    /**========================================================================
     *                           UPDATES
     *========================================================================**/
    public function update_orden_trabajo()
    {
        $bodyData = $this->request->getPost();
        // return $this->response->setJSON(["message" => lang("App.global_alert_save_success"),  "data" => $bodyData]);
        $validated = $this->validation->run($bodyData, "orden_trabajo");
        if ($validated) {
            $r = $this->produccionService->init($bodyData["orden_trabajo_id"])->updateOrdenTrabajo($bodyData);
            return $this->response->setJSON(["message" => lang("App.global_alert_save_success"), "status" => $r, "data" => $bodyData]);
        } else {
            return $this->response->setJSON(["errors" => $this->validation->getErrors()])->setStatusCode(400);
        }
    }
    public function update_orden_trabajo_tarea()
    {
        $bodyData = $this->request->getPost();
        // return $this->response->setJSON(["message" => lang("App.global_alert_save_success"),  "data" => $bodyData]);
        $validated = $this->validation->run($bodyData, "orden_trabajo_tarea");
        if ($validated) {
            $r = $this->produccionService->updateOrdenTrabajoTarea($bodyData["orden_trabajo_tarea_id"], $bodyData);
            return $this->response->setJSON(["message" => lang("App.global_alert_save_success"), "status" => $r, "data" => $bodyData]);
        } else {
            return $this->response->setJSON(["errors" => $this->validation->getErrors()])->setStatusCode(400);
        }
    }
    public function update_orden_trabajo_date()
    {
        $bodyData = $this->request->getPost();
        // return $this->response->setJSON(["message" => lang("App.global_alert_save_success"),  "data" => $bodyData]);
        $validated = $this->validation->run($bodyData, "orden_trabajo_date");
        if ($validated) {
            $r = $this->produccionService->init($bodyData["orden_trabajo_id"])->updateOrdenTrabajoDate($bodyData);
            return $this->response->setJSON(["message" => lang("App.global_alert_save_success"), "status" => $r["status"], "user" => $r["user"], "data" => $bodyData]);
        } else {
            return $this->response->setJSON(["errors" => $this->validation->getErrors()])->setStatusCode(400);
        }
    }
    public function update_orden_trabajo_pedido_date()
    {
        try {
            $bodyData = $this->request->getPost();
            $r = $this->produccionService->init($bodyData["orden_trabajo_id"])->updateOrdenTrabajoPedidoDate($bodyData);
            return $this->response->setJSON(["message" => lang("App.global_alert_save_success"), "status" => $r["status"], "user" => $r["user"], "data" => $bodyData]);
        } catch (\Throwable $th) {
            return $this->response->setJSON(["errors" => $th->getMessage(), "status" => false])->setStatusCode(500);
        }
    }
    public function update_orden_trabajo_pedido()
    {
        try {
            $bodyData = $this->request->getPost();
            $r = $this->produccionService->init($bodyData["orden_trabajo_id"])->updateOrdenTrabajoPedido($bodyData);
            return $this->response->setJSON(["message" => lang("App.global_alert_save_success"), "status" => $r, "data" => $bodyData]);
        } catch (\Throwable $th) {
            return $this->response->setJSON(["errors" => $th->getMessage(), "status" => false])->setStatusCode(500);
        }
    }
    public function edit($orden_trabajo_id)
    {
        // Breadcrumbs
        $this->viewData['breadcrumb'] = [
            ['title' => lang("Produccion.ot"), 'route' => site_url('produccion/ordentrabajo'), 'active' => false],
            ['title' => $this->otModel->find($orden_trabajo_id)->pedido()->presupuesto()->titulo, 'route' => site_url('produccion/ordentrabajo/edit/' . $orden_trabajo_id), 'active' => true]
        ];
        $this->viewData["modelId"] = $orden_trabajo_id;
        $this->produccionService->init($orden_trabajo_id);
        $this->produccionService->reInsertOrdenTrabajoDates();
        $this->produccionService->reInsertOrdenTrabajoUsers();
        $this->viewData["presupuesto"] = $this->produccionService->getPresupuesto();
        $this->viewData["cliente"] = $this->produccionService->getCliente();
        $this->viewData["ot"] = $this->produccionService->getOrdenTrabajo();
        $this->viewData["is_finalizada"] = $this->produccionService->getOrdenTrabajo()->estado == "F";
        $this->viewData["user_dates"] = $this->produccionService->userDates();
        $this->viewData["pedido_user_dates"] = $this->produccionService->pedidoUserDates();
        $this->viewData["colors"] = $this->produccionService->getPdfColors();
        $this->viewData["tiempo_estimado"] = $this->produccionService->getTiempoProcesamientoHHMM();
        $this->viewData["flags"] = $this->produccionService->getFlags();


        return view(static::$viewPath . $this->editRoute, $this->viewData);
    }

    public function datatable()
    {
        $logo = config(LogoImpresion::class);

        $q = $this->otModel->getDatatableQuery()->where("ordenes_trabajo.estado", "F");
        // return $this->response->setJSON($q->get()->getResultArray());
        return DataTable::of($q)
            ->add("logo", fn($q) => ["logo" => site_url($logo->get_logo_path($q->presupuesto_linea_tipo)), "imposicion" => $q->imposicion_name,"color" =>  $this->produccionService->init($q->id)->getOtColorStatus()])
            ->edit(
                "fecha_encuadernado_at",
                fn($q) => $q->fecha_encuadernado_at ? Time::createFromFormat("Y-m-d H:i:s", $q->fecha_encuadernado_at)->format("d/m/Y") : ""
            )
            ->add("action", fn($q) => $q->id)
            ->toJson(true);
    }
    public function datatable_pendientes()
    {
        $logo = config(LogoImpresion::class);

        $q = $this->otModel->getDatatableQuery()->whereIn("ordenes_trabajo.estado", ["I", "PM"]);
        // return $this->response->setJSON($q->get()->getResultArray());
        return DataTable::of($q)
            ->add("logo", fn($q) => ["logo" => site_url($logo->get_logo_path($q->presupuesto_linea_tipo)), "imposicion" => $q->imposicion_name,"color" =>  $this->produccionService->init($q->id)->getOtColorStatus()])
            ->edit(
                "fecha_encuadernado_at",
                fn($q) => $q->fecha_encuadernado_at ? Time::createFromFormat("Y-m-d H:i:s", $q->fecha_encuadernado_at)->format("d/m/Y") : ""
            )
            ->add("action", fn($q) => $q->id)
            ->toJson(true);
    }
    public function datatable_ferro_pendiente()
    {
        $logo = config(LogoImpresion::class);

        $q = $this->otModel->getDatatableQuery()->where("ferro_ok_at", null);
        // return $this->response->setJSON($q->get()->getResultArray());
        return DataTable::of($q)
            ->add("logo", fn($q) => ["logo" => site_url($logo->get_logo_path($q->presupuesto_linea_tipo)), "imposicion" => $q->imposicion_name,"color" =>  $this->produccionService->init($q->id)->getOtColorStatus()])
            ->edit(
                "fecha_encuadernado_at",
                fn($q) => $q->fecha_encuadernado_at ? Time::createFromFormat("Y-m-d H:i:s", $q->fecha_encuadernado_at)->format("d/m/Y") : ""
            )
            ->add("action", fn($q) => $q->id)
            ->toJson(true);
    }
    public function datatable_ferro_ok()
    {
        $logo = config(LogoImpresion::class);

        $q = $this->otModel->getDatatableQuery()->where("ferro_ok_at is NOT NULL", NULL, FALSE);
        // return $this->response->setJSON($q->get()->getResultArray());
        return DataTable::of($q)
            ->add("logo", fn($q) => ["logo" => site_url($logo->get_logo_path($q->presupuesto_linea_tipo)), "imposicion" => $q->imposicion_name,"color" =>  $this->produccionService->init($q->id)->getOtColorStatus()])
            ->edit(
                "fecha_encuadernado_at",
                fn($q) => $q->fecha_encuadernado_at ? Time::createFromFormat("Y-m-d H:i:s", $q->fecha_encuadernado_at)->format("d/m/Y") : ""
            )
            ->add("action", fn($q) => $q->id)
            ->toJson(true);
    }
    public function papel_gramaje_datatable()
    {

        $q = $this->produccionService->papelGramajeDatatableQuery();
        return DataTable::of($q)
            ->edit("tiempoReal", fn($q) => $q->tiempoReal)
            ->add("action", fn($q) => ["title" => lang('Produccion.datatable.filter_by_paper'), 'data' => $q])
            ->toJson(true);
    }
    public function papel_pliego_datatable()
    {

        $q = $this->produccionService->papelPliegoDatatableQuery();
        return DataTable::of($q)
            ->edit("tiempoReal", fn($q) => $q->tiempoReal)
            ->add("action", fn($q) => ["title" => lang('Produccion.datatable.filter_by_paper'), 'data' => $q])
            ->toJson(true);
    }
    public function reset_tareas(int $orden_trabajo_id)
    {
        $r = $this->produccionService->init($orden_trabajo_id)->resetAllTareas();
        return $this->response->setJSON(["message" => "Tareas reseteadas", "status" => $r]);
    }
    public function delete_tarea(int $orden_trabajo_tarea_id)
    {
        $r = $this->otTarea->delete($orden_trabajo_tarea_id);
        return $this->response->setJSON(["message" => "Tarea eliminada", "states" => $r]);
    }
    public function tareas_datatable(int $orden_trabajo_id)
    {
        $q = $this->produccionService->init($orden_trabajo_id)->taskDatatableQuery($orden_trabajo_id);
        // return $this->response->setJSON($q->get()->getResultArray());
        return DataTable::of($q)
            ->add("action", fn($q) => $q)
            ->edit("orden", fn($q) => ["id" => $q->id, "orden" => $q->orden])
            ->edit("tiempo_estimado", fn($q) => float_seconds_to_hhmm_string($q->tiempo_estimado))
            ->edit("tiempo_real", fn($q) => float_seconds_to_hhmm_string($q->tiempo_real))
            ->edit("maquina_tarea", fn($q) => ["id" => $q->id, "maquina_id" => $q->maquina_tarea, "maquina_name" => $q->maquina_nombre])
            ->add("imposicion", fn($q) => ["id" => $q->id, "imposicion_id" => $q->imposicion_id, "name" => $q->imposicion_name, "is_presupuesto_linea" => $q->presupuesto_linea_id ? true : false])
            ->toJson(true);
    }
    public function get_pdf($orden_trabajo_id)
    {
        return $this->produccionService->init($orden_trabajo_id)->getPdf();
    }
    public function upload_orden_trabajo_portada()
    {
        try {
            $file = $this->request->getFile("portada_file");
            $bodyData = $this->request->getPost();
            $id = $bodyData["orden_trabajo_id"];
            $r = null;
            $fullpath = null;
            if ($file->isValid() && !$file->hasMoved()) {
                $fullpath = $file->store('ordenes_trabajo_portadas');
                $otEntity = $this->otModel->find($id);
                if ($otEntity->portada_path) {
                    if (file_exists($otEntity->full_path)) {
                        unlink($otEntity->full_path);
                    }
                }
                $r = $this->otModel->update($id, ["portada_path" => $fullpath]);
            }
            return $this->response->setJSON(["message" => "Portada subida", "data" => $r]);
        } catch (\Throwable $th) {
            if ($fullpath) {
                delete_files($fullpath);
            }
            return $this->response->setJSON(["message" => "Portada error", "error" => $th->getMessage()])->setStatusCode(500);
        }
    }
    public function delete_orden_trabajo_portada($orden_trabajo_id)
    {
        try {
            helper('filesystem');
            $otEntity = $this->otModel->find($orden_trabajo_id);
            $pathActualFile = $otEntity->portada_path;
            $fullPath = WRITEPATH . 'uploads/' . $pathActualFile;
            if (file_exists($fullPath)) {
                delete_files($fullPath);
            }
            $r = $this->otModel->update($otEntity->id, ["portada_path" => null]);
            return $this->response->setJSON(["message" => "Portada eliminada", "data" => $r]);
        } catch (\Throwable $th) {
            return $this->response->setStatusCode(500)->setJSON(["message" => "Portada error", "error" => $th->getMessage()]);
        }
    }
    public function get_portada_img($orden_trabajo_id)
    {
        try {
            $ot = $this->otModel->find($orden_trabajo_id);
            if ($ot->portada_path) {
                $filePath = $ot->full_path;
                if (file_exists($filePath)) {

                    $mimeType = mime_content_type($filePath);
                    return $this->response
                        ->setHeader('Content-Type', $mimeType)
                        ->setHeader('Content-Length', filesize($filePath))
                        ->setBody(file_get_contents($filePath));
                } else {
                    throw new Exception('File' . $ot->portada_path . ' does not exist');
                }
            } else {
                return $this->response->setJSON(["message" => "Portada error", "error" => "No hay portada"])->setStatusCode(400);
            }
        } catch (\Throwable $th) {
            return $this->response->setJSON(["message" => "Portada error", "error" => $th->getMessage()])->setStatusCode(500);
        }
    }
    public function planning_rotativa_datatable()
    {
        $query = $this->produccionService->planningRotativaQueryDatatable();
        return DataTable::of($query)
            ->edit("fecha_entrega_real_at", fn($q) => $q->fecha_entrega_real_at ? Time::createFromFormat("Y-m-d", $q->fecha_entrega_real_at)->format("d/m/Y") : "")
            ->add("metros_check", fn($q) => $q->otId)
            ->add("corte", fn($q) => ["otId" => $q->otId, "tipo_corte" => $this->produccionService->ordenTrabajoTareaCorte($q->otId)])
            ->add("action", fn($q) => ["data" => $q])
            ->toJson(true);
    }
    public function planning_plana_datatable()
    {
        $query = $this->produccionService->planningPlanaQueryDatatable();
        $padreId = $this->request->getGet('padre_id');
        if ($padreId) {
            $query->where('lg_maquinas.padre_id', $padreId);
        }
        return DataTable::of($query)
            ->edit("tiempo_real_sum", fn($q) => $q->tiempo_real_sum)
            ->edit("fecha_entrega_real_at", fn($q) => $q->fecha_entrega_real_at ? Time::createFromFormat("Y-m-d", $q->fecha_entrega_real_at)->format("d/m/Y") : "")
            ->add("pliegos_check", fn($q) => $q->otId)
            ->add("action", fn($q) => ["data" => $q ])
            ->toJson(true);
    }
    public function select_maquina_planning_rot()
    {
        $q = $this->request->getGet('q');
        $result = $this->produccionService->querySelectMaquinaPlanningRotativa($q);
        return $this->response->setJSON($result);
    }
    public function select_papel_planning_rot()
    {
        $q = $this->request->getGet('q');
        $result = $this->produccionService->querySelectPapelPlanningRot($q);
        return $this->response->setJSON($result);
    }
    public function select_maquina_planning_plana()
    {
        $q = $this->request->getGet('q');
        $result = $this->produccionService->querySelectMaquinaPlanningPlana($q);
        return $this->response->setJSON($result);
    }
    public function select_maquina_padre_planning_plana()
    {
        $q = $this->request->getGet('q');
        $result = $this->produccionService->querySelectMaquinaPadrePlanningPlana($q);
        return $this->response->setJSON($result);
    }
    public function select_papel_planning_plana()
    {
        $q = $this->request->getGet('q');
        $result = $this->produccionService->querySelectPapelPlanningPlana($q);
        return $this->response->setJSON($result);
    }
    public function tarea_toggle_corte($orden_trabajo_id)
    {
        $status = $this->produccionService->tareaUpdateMaquinaCorte($orden_trabajo_id);
        return $this->response->setJSON(["message" => lang("App.global_alert_save_success"), "status" => $status]);
    }
    public function get_files()
    {
        $bodyData = $this->request->getPost();
        $files = $this->produccionService->init($bodyData["orden_trabajo_id"])->getOtFiles();
        $response = [];
        foreach ($files as $key => $file) {
            $file_ci4 = new File($file->file_path);
            $response[] = [
                "name" => $file->name,
                "size" => $file_ci4->getSize(),
                "hash" => $file->hash()
            ];
        }
        return json_encode($response);
    }
    public function upload_files()
    {
        try {
            //code...
            $otFiles = [];
            $bodyData = $this->request->getPost();
            $files = $this->request->getFileMultiple('file');
            $ps = $this->produccionService->init($bodyData["orden_trabajo_id"]);
            $existingFiles = json_decode($bodyData["oldFiles"]);
            $ps->deleteOtFiles($existingFiles);
            if ($files) {
                $response = $ps->storeOtFiles($files);
            } else {
                $response = null;
            }
            return $this->response->setJSON([
                "message" => lang("App.global_alert_save_success"),
                "data" => $response,
                "status" => true
            ]);
        } catch (\Throwable $th) {
            return $this->response->setJSON(
                [
                    "message" => lang("App.global_alert_save_error"),
                    "data" => $th,
                    "error" => $th->getMessage(),
                    "status" => false
                ]
            );
        }
    }
    public function get_orden_trabajo_color_status(int $orden_trabajo_id)
    {
        $color = $this->produccionService->init($orden_trabajo_id)->getOtColorStatus();
        return $this->response->setJSON(["color" => $color]);
    }
    public function imprimir_codigo_safekat(int $orden_trabajo_id)
    {
        helper('file');
        $barcode = $this->produccionService->init($orden_trabajo_id)->getFileBarCode();
        return $this->response
        ->setHeader('Content-Type', 'image/png')
        ->setHeader('Content-Disposition', "attachment; filename=CodigoBarrasOT_{$orden_trabajo_id}.png")
        ->setBody($barcode);
    }
    public function maquinista_maquinas_view(){}
    public function maquinista_colas_view(){}

}
