<?php

namespace App\Services;

use App\Core\Middlewares\Authentication;
use App\Models\Document;
use App\Repositories\EvidenceRepository;
use App\Repositories\StageRepository;
use Exception;

class EvidenceService {

    private EvidenceRepository $evidenceRepository;
    private StageRepository $stageRepository;

    public function __construct(){
        $this->evidenceRepository = new EvidenceRepository();
        $this->stageRepository = new StageRepository();
    }

    public function getDocument(int $documentId): ?Document
    {
        return $this->evidenceRepository->findById($documentId);
    }

    public function getDocumentsForStage(int $stageId): array
    {
        return $this->evidenceRepository->findByStageId($stageId);
    }

    public function submitEvidence(Document $document) 
    {
        $stage = $this->stageRepository->findBy('id', $document->stage_id);
        
        if(!$stage){
            throw new Exception("Etapa no encontrada.", 404);
        }

        $stagePath = $this->getStageFullPath($stage->project_id, $stage);
        $storagePath = $stagePath . '/';
        
        if (!is_dir($storagePath)) {
            mkdir($storagePath, 0777, true); // crear carpeta si no existe
        }

        $filename = time() . '_' . basename($document->file_name);
        $targetPath = $storagePath . $filename;

        if (!move_uploaded_file($document->file_tmp, $targetPath)) {
            return false; 
        }

        $relativePath = str_replace(__DIR__ . '/../../', '', $stagePath);
        $document->file_name = $filename;
        $document->file_path = '/' . $relativePath . '/' . $filename;

        $user = Authentication::user();
        $document->uploaded_by = $user->id;

        return $this->evidenceRepository->submit($document);
    }

    private function getStageFullPath(int $projectId, $stage): string
    {
        $project = $this->stageRepository->getProjectBy($stage->id);
        if (!$project) {
            throw new Exception("No se pudo obtener la información del proyecto.", 500);
        }
        
        $sanitizedProjectName = $this->sanitizeFolderName($project->name);
        $basePath = __DIR__ . '/../../Storage/projects/' . $sanitizedProjectName;
        $pathParts = [$this->sanitizeFolderName($stage->name)];
        
        $currentParentId = $stage->parent_id;
        while ($currentParentId !== null) {
            $parentStage = $this->stageRepository->findBy('id', $currentParentId);
            if ($parentStage) {
                array_unshift($pathParts, $this->sanitizeFolderName($parentStage->name));
                $currentParentId = $parentStage->parent_id;
            } else {
                break;
            }
        }
        
        return $basePath . '/' . implode('/', $pathParts);
    }
    private function sanitizeFolderName(string $name): string
    {
        $name = preg_replace('/[<>:"\/\\\\|?*]/', '_', $name);

        $name = trim($name);

        $name = preg_replace('/\s+/', ' ', $name);
        
        return $name;
    }
    
    public function deleteDocument(int $documentId): bool
    {
        $document = $this->evidenceRepository->findById($documentId);
        if (!$document) {
            throw new Exception("Documento no encontrado.", 404);
        }

        $filePath = __DIR__ . '/../../' . $document->file_path;

        if (file_exists($filePath)) {
            unlink($filePath);
        }

        if(!$this->evidenceRepository->delete($documentId)){
            throw new Exception("Error al eliminar el documento de la base de datos.", 500);
        }

        return true;
    } 
}