<?php

namespace FacturaScripts\Plugins\Partes\Model;

use FacturaScripts\Core\Base\DataBase\DataBaseWhere;
use FacturaScripts\Core\Model\Base\ModelClass;
use FacturaScripts\Core\Model\Base\ModelTrait;
use FacturaScripts\Core\Session;
use FacturaScripts\Core\Tools;
use FacturaScripts\Dinamic\Model\Proyecto;
use FacturaScripts\Dinamic\Model\OIUser;
use FacturaScripts\Dinamic\Model\OIFichajes;
use FacturaScripts\Dinamic\Model\TareaProyecto;
use FacturaScripts\Dinamic\Model\FaseTarea;
use FacturaScripts\Core\Model\AttachedFileRelation;
use FacturaScripts\Dinamic\Model\AttachedFile;
use FacturaScripts\Plugins\Notificaciones\Lib\NotificationNotice;
use FacturaScripts\Dinamic\Lib\Email\TextBlock;
use FacturaScripts\Dinamic\Lib\Email\SpaceBlock;
use FacturaScripts\Dinamic\Model\UsuariosNotificaciones;
use FacturaScripts\Plugins\Partes\Model\Categoria;
use FacturaScripts\Plugins\Partes\Lib\UploadManager;
use FacturaScripts\Plugins\Partes\Services\Task\TaskAttachmentService;
use FacturaScripts\Plugins\Partes\Services\Task\TaskChecklistService;
use FacturaScripts\Plugins\Partes\Services\Task\TaskContext;
use FacturaScripts\Plugins\Partes\Services\Task\TaskOperarioService;
use FacturaScripts\Plugins\Partes\Services\Task\TaskPersistenceService;
use FacturaScripts\Plugins\Partes\Services\Task\TaskUpdateService;

class Partes extends ModelClass
{
    use ModelTrait;

    /** @var string */
    public $creationdate;

    /** @var int */
    public $id;

    /** @var string */
    public $lastnick;

    /** @var string */
    public $lastupdate;

    /** @var string */
    public $nick;

    /** @var int */
    public $idproyecto;



    public function clear()
    {
        parent::clear();
        $this->creationdate = date(self::DATETIME_STYLE);
        $this->nick = Session::get('user')->nick ?? null;
    }

    public function getProyecto(): Proyecto
    {
        $proyecto = new Proyecto();
        $proyecto->loadFromCode($this->idproyecto);
        return $proyecto;
    }

    public function getVehiculos(): array
    {
        $vehiculo = new OIVehiculoOrden();
        $where = [new DataBaseWhere('idorden', $this->id)];
        return $vehiculo->all($where);
    }

    public function getMaterialPte(): array
    {
        $material = new OIMaterialProyecto();
        $where = [new DataBaseWhere('idproyecto', $this->idproyecto)];
        return $material->all($where);
    }

    public function getIncidencias(): array
    {
        $incidencia = new OIncidencia();
        $where = [new DataBaseWhere('idorden', $this->id)];
        return $incidencia->all($where);
    }


    public static function primaryColumn(): string
    {
        return "id";
    }

    public static function tableName(): string
    {
        return "ordenes_instalacion";
    }

    public function test(): bool
    {
        $this->lastnick = Tools::noHtml($this->lastnick);
        $this->nick = Tools::noHtml($this->nick);
        return parent::test();
    }

    protected function saveInsert(array $values = []): bool
    {
        $this->lastupdate = null;
        $this->lastnick = null;
        $return = parent::saveInsert($values);
	return $return;
    }

    protected function saveUpdate(array $values = []): bool
    {
        $this->lastupdate = Tools::dateTime();
        $this->lastnick = Session::user()->nick;
        return parent::saveUpdate($values);
    }


	public function getFases()
	{
		return (new FaseTarea)->all();

	}

	public function getImagenesMaterial()
	{
		$material = new OIMaterialProyecto();
		$where = [new DataBaseWhere('idproyecto', $this->idproyecto)];
		$materiales = $material->all($where);

		$return = [];

		foreach($materiales as $material){

			$archivosTareas = new \FacturaScripts\Dinamic\Model\AttachedFile();
			$where = [
				new DataBaseWhere('idmaterial', $material->id),
			];
			$files = $archivosTareas->all($where);
			foreach($files as $file){
				$return[] = $file;
			}
		}
		return $return;
	}

	public function getPlanos()
	{

		$return = [];

		$where = [
			new DataBaseWhere('model', "Proyecto"),
			new DataBaseWhere('modelcode', $this->idproyecto),
			new DataBaseWhere('modelid', $this->idproyecto),
		];
		$fileRelation = new AttachedFileRelation();
		$planosRelation = $fileRelation->all($where);

		foreach($planosRelation as $planoRelation)
		{
			$where = [
				new DataBaseWhere('idfile', $planoRelation->idfile),
			];
			$newFile = new AttachedFile();
			$files = $newFile->all($where);
			foreach($files as $file){
				$file->observations = $planoRelation->observations;
				$return[] = $file;
			}
		}

		return $return;

	}

	public function getTareas($idorden=null)
	{
		$this->getPlanos();

		$return = [
			"tarea" => []
		];


		$task = new \FacturaScripts\Dinamic\Model\TareaProyecto();
		$where = [
			new DataBaseWhere('idproyecto', $this->idproyecto)
		];
		$tasks = $task->all($where);

		foreach($tasks as $task){

			if($task->idfase > 2){
				continue;
			}

			//si no es subtarea
			if($task->idtareapadre == ""){
				$return["tarea"][$task->idtarea] = $task;
			}
		}

		foreach($return["tarea"] as $tarea){

			if($idorden){
				if($tarea->idorden != $idorden){
					continue;
				}
			}

			$task = new \FacturaScripts\Dinamic\Model\TareaProyecto();
			$where = [
				new DataBaseWhere('idtareapadre', $tarea->idtarea)
			];
			$subtasks = $task->all($where);
			foreach($subtasks as $subTarea){

				$comentariosTareas = new \FacturaScripts\Dinamic\Model\OiComentariosTareas();
				$where = [
					new DataBaseWhere('idtarea', $subTarea->idtarea)
				];
				$comentariosTareas = $comentariosTareas->all($where);
				foreach($comentariosTareas as $comentario){
					$saveInfo = $this->decodeHtmlEntity($comentario->comentario);
					if($saveInfo)
						$subTarea->comentarios[] = $saveInfo;
				}

				$operarioSubTarea = new \FacturaScripts\Plugins\Partes\Model\OIOperarioTarea();
				$where = [new DataBaseWhere('idtarea', $subTarea->idtarea)];
				$operariosModel = $operarioSubTarea->all($where);

				$subTarea->operarios = "";
				foreach($operariosModel as $operarioSubTarea){
					$subTarea->operarios = $operarioSubTarea->nick;
				}


				$archivosTareas = new \FacturaScripts\Dinamic\Model\AttachedFile();
				$where = [
					new DataBaseWhere('idtarea', $subTarea->idtarea),
				];
				$subTarea->files = $archivosTareas->all($where);

				$return["tarea"][$tarea->idtarea]->subtareas[] = $subTarea;
			}

			$archivosTareas = new \FacturaScripts\Dinamic\Model\AttachedFile();
			$where = [
				new DataBaseWhere('idtarea', $tarea->idtarea),
			];
			$archivosTareas = $archivosTareas->all($where);
			$return["tarea"][$tarea->idtarea]->files = $archivosTareas;

			$comentariosTareas = new \FacturaScripts\Dinamic\Model\OiComentariosTareas();
			$where = [
				new DataBaseWhere('idtarea', $tarea->idtarea)
			];
			$comentariosTareas = $comentariosTareas->all($where);
			foreach($comentariosTareas as $comentario){
				$saveInfo = $this->decodeHtmlEntity($comentario->comentario);
				if($saveInfo)
					$tarea->comentarios[] = $saveInfo;
			}

			$return["tarea"][$tarea->idtarea]->fichajes = (new OiFichajes)->getFichajes($tarea->idtarea);

			$operarioSubTarea = new \FacturaScripts\Plugins\Partes\Model\OIOperarioTarea();
			$where = [new DataBaseWhere('idtarea', $tarea->idtarea)];
			$operarios = $operarioSubTarea->all($where);
			$return["tarea"][$tarea->idtarea]->operarios = $operarios;


			$where = [new DataBaseWhere('id', $tarea->idcategoria)];
			$categorias = (new Categoria)->all($where);

			$categoriaTarea = "";

			if($categorias){
				$categoriaTarea = $categorias[0]->categoria;
			}
		
			$return["tarea"][$tarea->idtarea]->categoria = $categoriaTarea;

			$return["tarea"][$tarea->idtarea]->fichaje_pendiente = $this->verificarFichajePendiente($tarea->idtarea);
		}

		$return['operariosList'] = (new OIUser)->getOperarios();

		return $return;

	}

	private function verificarFichajePendiente($idtarea): ?OIFichajes
	{
		$nick = Session::get('user')->nick; // Obtener el usuario actual
		$fichajes = new OIFichajes();

		$where = [
			new DataBaseWhere('idtarea', $idtarea), // Coincidir por tarea
			new DataBaseWhere('nick', $nick),      // Coincidir por usuario
			new DataBaseWhere('fin', null, '=', 'AND') // Verificar que 'fin' sea NULL
		];

		// Buscar registros que coincidan
		$fichajesPendientes = $fichajes->all($where);

		// Retornar el primero encontrado o NULL si no hay ninguno
		return !empty($fichajesPendientes) ? $fichajesPendientes[0] : null;
	}


	public function actualizarTarea()
	{
		$context = TaskContext::fromRequest($_POST ?? [], $_FILES ?? []);

		if (!$context->shouldProcess()) {
			return null;
		}

		$service = new TaskUpdateService(
			new TaskPersistenceService($this),
			new TaskOperarioService($this),
			new TaskChecklistService($this),
			new TaskAttachmentService($this)
		);

		return $service->handle($context);
	}


	function saveComentarios($comentarios = null, $idTarea=null){

		if ($comentarios) {
			$comentariosTareas = new \FacturaScripts\Dinamic\Model\OiComentariosTareas();
			$comentariosTareas->comentario = $comentarios;
			$comentariosTareas->idtarea = $idTarea;
			$comentariosTareas->save();
		}
	}

	    public static function deleteAttachmentsByIdentifiers(array $entries): void
    {
        foreach ($entries as $entry) {
            foreach (self::fetchAttachmentsByIdentifier($entry) as $archivo) {
                $archivo->delete();
            }
        }
    }

	public function guardarImagenTarea($files, $idtarea): int
	{
		$isArray = is_array($files);
		$tmpNames = $isArray && isset($files['tmp_name']) ? (array) $files['tmp_name'] : null;
		$names = $isArray && isset($files['name']) ? (array) $files['name'] : [];

		if (!$isArray || !is_array($tmpNames)) {
			return 0;
		}

		$ids = is_array($idtarea) ? $idtarea : array_fill(0, count($tmpNames), $idtarea);
		$guardados = 0;

		foreach ($tmpNames as $key => $tmpName) {
			$name = $names[$key] ?? null;
			$targetId = self::normalizeAttachmentId($ids[$key] ?? null);
			$single = [
				'name' => [$name],
				'tmp_name' => [$tmpName],
			];

			try {
				$guardados += UploadManager::upload($single, 'idtarea', $targetId);
			} catch (\Throwable $exception) {
				Tools::log('partes')->warning('No se pudo guardar el archivo adjunto', [
					'nombre' => $name,
					'tmp' => $tmpName,
					'idtarea' => $targetId,
					'error' => $exception->getMessage(),
				]);
			}
		}

		return $guardados;
	}

	public function decodeHtmlEntity($str) {

		$str = strip_tags($str);

		$entities = array(
				'lt' => '<',
				'gt' => '>',
				'amp' => '&',
				);

		$return = preg_replace_callback('/&([a-z]+);/i', function($match) use ($entities) {
				return isset($entities[$match[1]]) ? $entities[$match[1]] : $match[0];
				}, $str);
		return strip_tags($return);


	}

	public static function normalizeAttachmentTokenList($value): array
	{
		if ($value === null || $value === '') {
			return [];
		}

		if (is_string($value)) {
			$decoded = json_decode($value, true);
			if (json_last_error() === JSON_ERROR_NONE) {
				return self::normalizeAttachmentTokenList($decoded);
			}

			$parts = array_map('trim', explode(',', $value));
			return array_values(array_filter($parts, static function ($token) {
				return $token !== '';
			}));
		}

		if (is_array($value)) {
			$result = [];
			foreach ($value as $item) {
				foreach (self::normalizeAttachmentTokenList($item) as $token) {
					if (!in_array($token, $result, true)) {
						$result[] = $token;
					}
				}
			}
			return $result;
		}

		$token = trim((string) $value);
		return $token === '' ? [] : [$token];
	}

	public static function normalizeAttachmentTokenMap($value): array
	{
		if ($value === null || $value === '') {
			return [];
		}

		if (is_string($value)) {
			$decoded = json_decode($value, true);
			if (json_last_error() === JSON_ERROR_NONE) {
				return self::normalizeAttachmentTokenMap($decoded);
			}
			return [];
		}

		if (!is_array($value)) {
			return [];
		}

		$result = [];

		if (!array_is_list($value)) {
			foreach ($value as $key => $tokens) {
				$key = trim((string) $key);
				if ($key === '') {
					continue;
				}

				$normalizedTokens = self::normalizeAttachmentTokenList($tokens);
				if (!empty($normalizedTokens)) {
					if (isset($result[$key])) {
						$result[$key] = array_values(array_unique(array_merge($result[$key], $normalizedTokens)));
						continue;
					}

					$result[$key] = $normalizedTokens;
				}
			}

			return $result;
		}

		foreach ($value as $entry) {
			if (!is_array($entry)) {
				continue;
			}

			$id = $entry['idtarea'] ?? $entry['id'] ?? $entry['target'] ?? $entry['key'] ?? null;
			$tokens = $entry['tokens'] ?? $entry['values'] ?? $entry['files'] ?? null;

			if (null === $tokens && isset($entry['token'])) {
				$tokens = [$entry['token']];
			}

			if (null === $tokens && array_is_list($entry) && count($entry) >= 2) {
				$id = $entry[0];
				$tokens = array_slice($entry, 1);
			}

			if (null === $id || null === $tokens) {
				continue;
			}

			$key = trim((string) $id);
			if ($key === '') {
				continue;
			}

			$normalizedTokens = self::normalizeAttachmentTokenList($tokens);
			if (!empty($normalizedTokens)) {
				if (isset($result[$key])) {
					$result[$key] = array_values(array_unique(array_merge($result[$key], $normalizedTokens)));
					continue;
				}

				$result[$key] = $normalizedTokens;
			}
		}

		return $result;
	}

	public static function registerAttachmentTarget(array &$targets, $rawId, int $targetId): void
	{
		$candidates = [
			trim((string) $rawId),
			trim((string) $targetId),
		];

		$normalized = self::normalizeAttachmentId($rawId);
		if ($normalized !== 0) {
			$candidates[] = trim((string) $normalized);
		}

		foreach ($candidates as $candidate) {
			if ($candidate === '') {
				continue;
			}
			$targets[$candidate] = $targetId;
		}
	}

	public static function resolveAttachmentTargetId(array $targets, $rawId): ?int
	{
		$candidates = [
			trim((string) $rawId),
		];

		if (is_numeric($rawId)) {
			$candidates[] = (string) ((int) $rawId);
		}

		$normalized = self::normalizeAttachmentId($rawId);
		if ($normalized !== 0) {
			$candidates[] = (string) $normalized;
		}

		foreach ($candidates as $candidate) {
			if ($candidate === '') {
				continue;
			}

			if (isset($targets[$candidate])) {
				return (int) $targets[$candidate];
			}
		}

		return is_numeric($rawId) ? (int) $rawId : null;
	}

	public static function attachFilesByIdentifiers(array $entries, int $targetId): int
	{
		$processed = [];
		$attached = 0;

		foreach ($entries as $entry) {
			foreach (self::fetchAttachmentsByIdentifier($entry) as $archivo) {
				$idfile = (int) ($archivo->idfile ?? 0);
				if ($idfile > 0 && isset($processed[$idfile])) {
					continue;
				}

				if ((int) $archivo->idtarea !== $targetId) {
					$archivo->idtarea = $targetId;
					if (false === $archivo->save()) {
						continue;
					}
				}

				if ($idfile > 0) {
					$processed[$idfile] = true;
				}

				$attached++;
			}
		}

		return $attached;
	}

	private static function fetchAttachmentsByIdentifier($identifier): array
	{
		$identifier = trim((string) $identifier);
		if ($identifier === '') {
			return [];
		}

		if (is_numeric($identifier) && (string) (int) $identifier === $identifier) {
			$file = new AttachedFile();
			return $file->loadFromCode((int) $identifier) ? [$file] : [];
		}

		if (0 === strpos($identifier, 'tmp_')) {
			$tempId = self::normalizeAttachmentId($identifier);
			if (0 === $tempId) {
				return [];
			}

			$files = new AttachedFile();
			return $files->all([
				new DataBaseWhere('idtarea', $tempId)
			]);
		}

		$urlParts = explode('?myft=', $identifier);
		$path = $urlParts[0] ?? '';
		if (false !== strpos($path, 'MyFiles/')) {
			$path = substr($path, strpos($path, 'MyFiles/'));
		}
		$path = ltrim($path, '/');
		if ($path === '') {
			return [];
		}

		$archivosTareas = new AttachedFile();
		return $archivosTareas->all([
			new DataBaseWhere('path', $path)
		]);
	}

private static function decodeJsonArray($value): array
{
		if ($value === null) {
			return [];
		}

		if (!is_array($value)) {
			$value = [$value];
		}

		$result = [];
		foreach ($value as $item) {
			if (is_string($item)) {
				$decoded = json_decode($item, true);
				if (json_last_error() === JSON_ERROR_NONE) {
					$result[] = $decoded;
					continue;
				}
			}
			$result[] = $item;
		}

		return $result;
	}

	private static function flattenItems(array $items, array $requiredKeys): array
	{
		$result = [];
		$stack = $items;
		while ($stack) {
			$item = array_shift($stack);
			if (!is_array($item)) {
				continue;
			}

			$hasAllKeys = true;
			foreach ($requiredKeys as $key) {
				if (!array_key_exists($key, $item)) {
					$hasAllKeys = false;
					break;
				}
			}

			if ($hasAllKeys) {
				$result[] = $item;
				continue;
			}

			foreach ($item as $value) {
				if (is_array($value)) {
					$stack[] = $value;
				}
			}
		}

		return $result;
	}

	public static function normalizeChecklistItems($value): array
	{
		return self::flattenItems(self::decodeJsonArray($value), ['id', 'descripcion', 'marcado']);
	}

	public static function normalizeSubtaskItems($value): array
	{
		return self::flattenItems(self::decodeJsonArray($value), ['idtarea']);
	}

	public static function decodeJsonList($value): array
	{
		if (is_array($value)) {
			return $value;
		}

		if (is_string($value)) {
			$decoded = json_decode($value, true);
			if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
				return $decoded;
			}
		}

		return $value === null || $value === '' ? [] : [$value];
	}

	public static function normalizeAttachmentId($id): int
	{
		if (is_array($id)) {
			$id = reset($id);
		}

		if ($id === null || $id === '' || $id === false) {
			return 0;
		}

		if (is_numeric($id) && (string) (int) $id === trim((string) $id)) {
			return (int) $id;
		}

		$unsigned = (int) sprintf('%u', crc32((string) $id));
		$mod = $unsigned % 2000000000;
		if (0 === $mod) {
			$mod = 2000000000;
		}

		return -$mod;
	}

	        public function guardarImagenMaterial($files, $idMaterial)
	        {
	                UploadManager::upload($files, 'idmaterial', (int) $idMaterial);
	        }

        public function guardarIncidencia($files, $data)
        {
                $incidencia = new OIncidencia();
                $incidencia->idorden = $data['idorden'];
                $incidencia->descripcion_incidencia = $data['descripcion'];
                $incidencia->idproyecto = $data['idproyecto'];
                $incidencia->name = $data['titulo'];
                $incidencia->nick = Session::get('user')->nick;
                $incidencia->lastnick = Session::get('user')->nick;
                $incidencia->estado = "pendiente";
                $incidencia->save();

                $notificaciones = new UsuariosNotificaciones();
                $notificaciones->send(UsuariosNotificaciones::CREAR_INCIDENCIA, $incidencia);

                UploadManager::upload($files, 'idincidencia', (int) $incidencia->id);
        }

}
