<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Controller;
use App\Core\Database;
use App\Core\Permission;
use App\Foundation\Foundation;
use App\Foundation\HealthReport;
use App\Services\FeatureFlagService;
use App\Services\GeneratorRegistry;
use App\Services\StudioModuleService;
use App\Services\StudioEntityService;
use App\Services\StudioFormService;
use App\Services\StudioCrudGeneratorService;
use App\Services\StudioWorkflowService;
use App\Services\StudioDashboardService;
use App\Services\StudioReportService;
use App\Services\StudioApiService;
use App\Services\StudioRuleService;
use App\Services\StudioDocumentService;
use App\Core\Csrf;
use Throwable;

final class AxiomStudioController extends Controller
{
    public function index(): void
    {
        Auth::requireLogin();
        Permission::requireAny('updates.view', 'backups.view', 'administration.permissions.view', 'utilisateurs.view');

        $app = Foundation::app();
        /** @var HealthReport $healthReport */
        $healthReport = $app->container()->get(HealthReport::class);
        $checks = $healthReport->checks();

        $healthy = count(array_filter(
            $checks,
            static fn(array $check): bool => ($check['status'] ?? '') === 'ok'
        ));

        $dbVersion = 'indisponible';
        $databaseName = 'indisponible';
        try {
            $pdo = Database::connection();
            $dbVersion = (string)$pdo->query('SELECT VERSION()')->fetchColumn();
            $databaseName = (string)$pdo->query('SELECT DATABASE()')->fetchColumn();
        } catch (Throwable) {
            // Le diagnostic détaillé reste disponible dans Foundation.
        }

        $version = is_file(BASE_PATH . '/VERSION')
            ? trim((string)file_get_contents(BASE_PATH . '/VERSION'))
            : $app->version();

        $storageBytes = $this->directorySize(BASE_PATH . '/storage');
        $updateCount = $this->countRows('cda_update_packages');
        $backupCount = $this->countRows('cda_backup_jobs');

        $this->view('axiom_studio/index', [
            'pageTitle' => 'AXIOM Studio',
            'version' => $version,
            'modules' => $app->modules()->all(),
            'entities' => $app->metadata()->all(),
            'checks' => $checks,
            'healthy' => $healthy,
            'dbVersion' => $dbVersion,
            'databaseName' => $databaseName,
            'storageBytes' => $storageBytes,
            'updateCount' => $updateCount,
            'backupCount' => $backupCount,
        ]);
    }

    public function modules(): void
    {
        $this->requireStudioAccess();
        $this->view('axiom_studio/modules', [
            'pageTitle' => 'Modules — AXIOM Studio',
            'studioModules' => (new StudioModuleService())->all(),
            'runtimeModules' => Foundation::app()->modules()->all(),
        ]);
    }

    public function createModule(): void
    {
        $this->requireStudioAccess();
        $this->view('axiom_studio/module_create', [
            'pageTitle' => 'Nouveau module — AXIOM Studio',
        ]);
    }

    public function storeModule(): void
    {
        $this->requireStudioAccess();
        Csrf::verify($_POST['_csrf'] ?? null);
        try {
            (new StudioModuleService())->create($_POST, (int)($_SESSION['user']['id'] ?? 0) ?: null);
            $_SESSION['flash_success'] = 'Le projet de module a été créé dans AXIOM Studio.';
            $this->redirect('/administration/axiom/modules');
        } catch (\Throwable $e) {
            $_SESSION['flash_error'] = $e->getMessage();
            $_SESSION['studio_old'] = $_POST;
            $this->redirect('/administration/axiom/modules/nouveau');
        }
    }

    public function generators(): void
    {
        $this->requireStudioAccess();
        $this->view('axiom_studio/generators', [
            'pageTitle' => 'Générateurs — AXIOM Studio',
            'generators' => (new GeneratorRegistry())->all(),
        ]);
    }

    public function features(): void
    {
        $this->requireStudioAccess();
        $this->view('axiom_studio/features', [
            'pageTitle' => 'Fonctionnalités — AXIOM Studio',
            'flags' => (new FeatureFlagService())->all(),
        ]);
    }

    public function documentation(): void
    {
        $this->requireStudioAccess();
        $this->view('axiom_studio/documentation', [
            'pageTitle' => 'SDK — AXIOM Studio',
        ]);
    }


    public function entityDesigner(): void
    {
        $this->requireStudioAccess();
        $moduleId = (int)($_GET['module_id'] ?? 0);
        $entityId = (int)($_GET['entity_id'] ?? 0);
        $service = new StudioEntityService();
        $module = $service->module($moduleId);
        if (!$module) {
            $_SESSION['flash_error'] = 'Sélectionnez un projet de module valide.';
            $this->redirect('/administration/axiom/modules');
            return;
        }
        $entities = $service->entities($moduleId);
        if ($entityId <= 0 && $entities) {
            $entityId = (int)$entities[0]['id'];
        }
        $selectedEntity = $entityId > 0 ? $service->entity($entityId) : null;
        if ($selectedEntity && (int)$selectedEntity['module_id'] !== $moduleId) {
            $selectedEntity = null;
        }
        $this->view('axiom_studio/entity_designer', [
            'pageTitle' => 'Entity Designer — AXIOM Studio',
            'module' => $module,
            'entities' => $entities,
            'selectedEntity' => $selectedEntity,
            'fields' => $selectedEntity ? $service->fields((int)$selectedEntity['id']) : [],
            'relations' => $service->relations($moduleId),
            'preview' => $service->preview($moduleId),
            'fieldTypes' => $service->fieldTypes(),
        ]);
    }

    public function storeEntity(): void
    {
        $this->requireStudioAccess();
        Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId = (int)($_POST['module_id'] ?? 0);
        try {
            $entityId = (new StudioEntityService())->createEntity($moduleId, $_POST, $this->userId());
            $_SESSION['flash_success'] = 'L’entité a été ajoutée au modèle de données.';
            $this->redirect('/administration/axiom/entity-designer?module_id=' . $moduleId . '&entity_id=' . $entityId);
        } catch (\Throwable $e) {
            $_SESSION['flash_error'] = $e->getMessage();
            $this->redirect('/administration/axiom/entity-designer?module_id=' . $moduleId);
        }
    }

    public function storeField(): void
    {
        $this->requireStudioAccess();
        Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId = (int)($_POST['module_id'] ?? 0);
        $entityId = (int)($_POST['entity_id'] ?? 0);
        try {
            (new StudioEntityService())->createField($entityId, $_POST, $this->userId());
            $_SESSION['flash_success'] = 'Le champ a été ajouté à l’entité.';
        } catch (\Throwable $e) {
            $_SESSION['flash_error'] = $e->getMessage();
        }
        $this->redirect('/administration/axiom/entity-designer?module_id=' . $moduleId . '&entity_id=' . $entityId);
    }

    public function storeRelation(): void
    {
        $this->requireStudioAccess();
        Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId = (int)($_POST['module_id'] ?? 0);
        try {
            (new StudioEntityService())->createRelation($moduleId, $_POST, $this->userId());
            $_SESSION['flash_success'] = 'La relation a été ajoutée au modèle.';
        } catch (\Throwable $e) {
            $_SESSION['flash_error'] = $e->getMessage();
        }
        $this->redirect('/administration/axiom/entity-designer?module_id=' . $moduleId);
    }

    public function archiveDesignerObject(): void
    {
        $this->requireStudioAccess();
        Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId = (int)($_POST['module_id'] ?? 0);
        $entityId = (int)($_POST['entity_id'] ?? 0);
        try {
            (new StudioEntityService())->archive((string)($_POST['object_type'] ?? ''), (int)($_POST['object_id'] ?? 0), $this->userId());
            $_SESSION['flash_success'] = 'L’élément a été archivé.';
        } catch (\Throwable $e) {
            $_SESSION['flash_error'] = $e->getMessage();
        }
        $url = '/administration/axiom/entity-designer?module_id=' . $moduleId;
        if ($entityId > 0 && ($_POST['object_type'] ?? '') !== 'entity') {
            $url .= '&entity_id=' . $entityId;
        }
        $this->redirect($url);
    }


    public function formDesigner(): void
    {
        $this->requireStudioAccess();
        $moduleId=(int)($_GET['module_id']??0); $entityId=(int)($_GET['entity_id']??0); $service=new StudioFormService();
        $module=$service->module($moduleId); if(!$module){$_SESSION['flash_error']='Sélectionnez un module valide.';$this->redirect('/administration/axiom/modules');return;}
        $entities=$service->entities($moduleId); if($entityId<=0 && $entities){$entityId=(int)$entities[0]['id'];}
        $entity=$entityId>0?$service->entity($entityId):null; $formId=0;$components=[];
        if($entity && (int)$entity['module_id']===$moduleId){$formId=$service->ensureForm($moduleId,$entityId,$this->userId());$components=$service->components($formId);}
        $this->view('axiom_studio/form_designer',['pageTitle'=>'Form Designer — AXIOM Studio','module'=>$module,'entities'=>$entities,'entity'=>$entity,'fields'=>$entity?$service->fields($entityId):[],'formId'=>$formId,'components'=>$components,'preview'=>$service->preview($components)]);
    }
    public function storeFormComponent(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); $moduleId=(int)($_POST['module_id']??0);$entityId=(int)($_POST['entity_id']??0);$formId=(int)($_POST['form_id']??0);
        try{(new StudioFormService())->addComponent($formId,$_POST,$this->userId());$_SESSION['flash_success']='Le composant a été ajouté au formulaire.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/form-designer?module_id='.$moduleId.'&entity_id='.$entityId);
    }
    public function reorderFormComponents(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); $ids=json_decode((string)($_POST['order_json']??'[]'),true); if(!is_array($ids))$ids=[];(new StudioFormService())->saveOrder((int)($_POST['form_id']??0),$ids,$this->userId());
        $this->redirect('/administration/axiom/form-designer?module_id='.(int)($_POST['module_id']??0).'&entity_id='.(int)($_POST['entity_id']??0));
    }
    public function archiveFormComponent(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); (new StudioFormService())->archiveComponent((int)($_POST['component_id']??0),$this->userId());
        $this->redirect('/administration/axiom/form-designer?module_id='.(int)($_POST['module_id']??0).'&entity_id='.(int)($_POST['entity_id']??0));
    }


    public function crudGenerator(): void
    {
        $this->requireStudioAccess();
        $service=new StudioCrudGeneratorService();
        $moduleId=(int)($_GET['module_id']??0); $entityId=(int)($_GET['entity_id']??0);
        $modules=$service->modules();
        if($moduleId<=0 && $modules){$moduleId=(int)$modules[0]['id'];}
        $entities=$moduleId>0?$service->entities($moduleId):[];
        if($entityId<=0 && $entities){$entityId=(int)$entities[0]['id'];}
        $preview=null;
        if($moduleId>0 && $entityId>0){try{$preview=$service->preview($moduleId,$entityId);}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}}
        $this->view('axiom_studio/crud_generator',['pageTitle'=>'CRUD Generator — AXIOM Studio','modules'=>$modules,'moduleId'=>$moduleId,'entityId'=>$entityId,'entities'=>$entities,'preview'=>$preview,'history'=>$moduleId>0?$service->history($moduleId):[]]);
    }

    public function generateCrud(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null);
        $moduleId=(int)($_POST['module_id']??0); $entityId=(int)($_POST['entity_id']??0);
        try{$result=(new StudioCrudGeneratorService())->generate($moduleId,$entityId,$this->userId());$_SESSION['flash_success']='CRUD généré : '.(int)$result['count'].' artefacts enregistrés dans storage/generated.';}
        catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/crud-generator?module_id='.$moduleId.'&entity_id='.$entityId);
    }


    public function workflowDesigner(): void
    {
        $this->requireStudioAccess(); $service=new StudioWorkflowService();
        $moduleId=(int)($_GET['module_id']??0); $workflowId=(int)($_GET['workflow_id']??0); $modules=$service->modules();
        if($moduleId<=0 && $modules)$moduleId=(int)$modules[0]['id'];
        $workflows=$moduleId>0?$service->workflows($moduleId):[];
        if($workflowId<=0 && $workflows)$workflowId=(int)$workflows[0]['id'];
        $workflow=$workflowId>0?$service->workflow($workflowId):null;
        if($workflow && (int)$workflow['module_id']!==$moduleId)$workflow=null;
        $nodes=$workflow?$service->nodes($workflowId):[]; $transitions=$workflow?$service->transitions($workflowId):[];
        $this->view('axiom_studio/workflow_designer',['pageTitle'=>'Workflow Designer — AXIOM Studio','modules'=>$modules,'moduleId'=>$moduleId,'entities'=>$moduleId>0?$service->entities($moduleId):[],'workflows'=>$workflows,'workflow'=>$workflow,'nodes'=>$nodes,'transitions'=>$transitions,'nodeTypes'=>$service->nodeTypes(),'simulation'=>$workflow?$service->simulate($workflowId):null]);
    }

    public function storeWorkflow(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); $moduleId=(int)($_POST['module_id']??0);
        try{$id=(new StudioWorkflowService())->createWorkflow($moduleId,$_POST,$this->userId());$_SESSION['flash_success']='Workflow créé avec ses étapes Début et Fin.';$this->redirect('/administration/axiom/workflow-designer?module_id='.$moduleId.'&workflow_id='.$id);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/workflow-designer?module_id='.$moduleId);
    }

    public function storeWorkflowNode(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); $moduleId=(int)($_POST['module_id']??0);$workflowId=(int)($_POST['workflow_id']??0);
        try{(new StudioWorkflowService())->addNode($workflowId,$_POST,$this->userId());$_SESSION['flash_success']='Étape ajoutée au workflow.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/workflow-designer?module_id='.$moduleId.'&workflow_id='.$workflowId);
    }

    public function storeWorkflowTransition(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); $moduleId=(int)($_POST['module_id']??0);$workflowId=(int)($_POST['workflow_id']??0);
        try{(new StudioWorkflowService())->addTransition($workflowId,$_POST,$this->userId());$_SESSION['flash_success']='Transition ajoutée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/workflow-designer?module_id='.$moduleId.'&workflow_id='.$workflowId);
    }

    public function publishWorkflow(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); $moduleId=(int)($_POST['module_id']??0);$workflowId=(int)($_POST['workflow_id']??0);
        try{(new StudioWorkflowService())->publish($workflowId,$this->userId());$_SESSION['flash_success']='Workflow publié et figé dans une version exécutable.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/workflow-designer?module_id='.$moduleId.'&workflow_id='.$workflowId);
    }

    public function archiveWorkflowObject(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf']??null); $moduleId=(int)($_POST['module_id']??0);$workflowId=(int)($_POST['workflow_id']??0);
        try{(new StudioWorkflowService())->archive((string)($_POST['object_type']??''),(int)($_POST['object_id']??0),$this->userId());$_SESSION['flash_success']='Élément archivé.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/workflow-designer?module_id='.$moduleId.'&workflow_id='.$workflowId);
    }


    public function dashboardDesigner(): void
    {
        $this->requireStudioAccess(); $service=new StudioDashboardService();
        $moduleId=(int)($_GET['module_id']??0);$dashboardId=(int)($_GET['dashboard_id']??0);$modules=$service->modules();
        if($moduleId<=0&&$modules)$moduleId=(int)$modules[0]['id'];
        $dashboards=$moduleId>0?$service->dashboards($moduleId):[];
        if($dashboardId<=0&&$dashboards)$dashboardId=(int)$dashboards[0]['id'];
        $dashboard=$dashboardId>0?$service->dashboard($dashboardId):null;
        if($dashboard&&(int)$dashboard['module_id']!==$moduleId)$dashboard=null;
        $this->view('axiom_studio/dashboard_designer',['pageTitle'=>'Dashboard Designer — AXIOM Studio','modules'=>$modules,'moduleId'=>$moduleId,'dashboards'=>$dashboards,'dashboard'=>$dashboard,'widgets'=>$dashboard?$service->widgets($dashboardId):[],'entities'=>$moduleId>0?$service->entities($moduleId):[],'widgetTypes'=>$service->widgetTypes(),'dataSources'=>$service->dataSources()]);
    }

    public function storeDashboard(): void
    {
        $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$moduleId=(int)($_POST['module_id']??0);
        try{$id=(new StudioDashboardService())->createDashboard($moduleId,$_POST,$this->userId());$_SESSION['flash_success']='Tableau de bord créé.';$this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$id);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId);
    }

    public function storeDashboardWidget(): void
    {
        $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$moduleId=(int)($_POST['module_id']??0);$dashboardId=(int)($_POST['dashboard_id']??0);
        try{(new StudioDashboardService())->addWidget($dashboardId,$_POST,$this->userId());$_SESSION['flash_success']='Widget ajouté au tableau de bord.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$dashboardId);
    }

    public function reorderDashboardWidgets(): void
    {
        $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$moduleId=(int)($_POST['module_id']??0);$dashboardId=(int)($_POST['dashboard_id']??0);$ids=json_decode((string)($_POST['order_json']??'[]'),true);if(!is_array($ids))$ids=[];
        try{(new StudioDashboardService())->saveOrder($dashboardId,$ids,$this->userId());$_SESSION['flash_success']='Ordre des widgets enregistré.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$dashboardId);
    }

    public function publishDashboard(): void
    {
        $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$moduleId=(int)($_POST['module_id']??0);$dashboardId=(int)($_POST['dashboard_id']??0);
        try{(new StudioDashboardService())->publish($dashboardId,$this->userId());$_SESSION['flash_success']='Tableau de bord publié.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$dashboardId);
    }

    public function archiveDashboardObject(): void
    {
        $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$moduleId=(int)($_POST['module_id']??0);$dashboardId=(int)($_POST['dashboard_id']??0);
        try{(new StudioDashboardService())->archive((string)($_POST['object_type']??''),(int)($_POST['object_id']??0),$this->userId());$_SESSION['flash_success']='Élément archivé.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $url='/administration/axiom/dashboard-designer?module_id='.$moduleId;if(($_POST['object_type']??'')!=='dashboard')$url.='&dashboard_id='.$dashboardId;$this->redirect($url);
    }


    public function updateDashboard(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId=(int)($_POST['module_id']??0); $dashboardId=(int)($_POST['dashboard_id']??0);
        try{(new StudioDashboardService())->updateDashboard($dashboardId,$_POST,$this->userId());$_SESSION['flash_success']='Paramètres du tableau de bord enregistrés.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$dashboardId);
    }

    public function updateDashboardWidget(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId=(int)($_POST['module_id']??0); $dashboardId=(int)($_POST['dashboard_id']??0); $widgetId=(int)($_POST['widget_id']??0);
        try{(new StudioDashboardService())->updateWidget($dashboardId,$widgetId,$_POST,$this->userId());$_SESSION['flash_success']='Widget mis à jour.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$dashboardId);
    }

    public function duplicateDashboard(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId=(int)($_POST['module_id']??0); $dashboardId=(int)($_POST['dashboard_id']??0);
        try{$newId=(new StudioDashboardService())->duplicateDashboard($dashboardId,$this->userId());$_SESSION['flash_success']='Tableau de bord dupliqué.';$this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$newId);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/dashboard-designer?module_id='.$moduleId.'&dashboard_id='.$dashboardId);
    }


    public function documentDesigner(): void
    {
        $this->requireStudioAccess();$s=new StudioDocumentService();$moduleId=(int)($_GET['module_id']??0);$templateId=(int)($_GET['template_id']??0);$modules=$s->modules();if($moduleId<=0&&$modules)$moduleId=(int)$modules[0]['id'];$templates=$moduleId?$s->templates($moduleId):[];if($templateId<=0&&$templates)$templateId=(int)$templates[0]['id'];$template=$templateId?$s->template($templateId):null;if($template&&(int)$template['module_id']!==$moduleId)$template=null;$entities=$moduleId?$s->entities($moduleId):[];$entityId=(int)($_GET['entity_id']??($template['entity_id']??0));$sample=$s->sampleData($entityId);$rendered=$template?$s->render((int)$template['id'],$sample):['html'=>''];$this->view('axiom_studio/document_designer',['pageTitle'=>'Document Designer — AXIOM Studio','modules'=>$modules,'moduleId'=>$moduleId,'templates'=>$templates,'template'=>$template,'categories'=>$s->categories(),'entities'=>$entities,'entityId'=>$entityId,'variables'=>$s->variables($entityId),'sampleData'=>$sample,'rendered'=>$rendered,'versions'=>$template?$s->versions((int)$template['id']):[],'generated'=>$template?$s->generated((int)$template['id']):[]]);
    }
    public function saveDocumentTemplate(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);try{$id=(new StudioDocumentService())->save($m,$_POST,$this->userId());$_SESSION['flash_success']='Modèle documentaire enregistré.';$this->redirect('/administration/axiom/document-designer?module_id='.$m.'&template_id='.$id);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/document-designer?module_id='.$m); }
    public function publishDocumentTemplate(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$id=(int)($_POST['template_id']??0);try{(new StudioDocumentService())->publish($id,$this->userId());$_SESSION['flash_success']='Modèle publié.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/document-designer?module_id='.$m.'&template_id='.$id); }
    public function duplicateDocumentTemplate(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);try{$id=(new StudioDocumentService())->duplicate((int)($_POST['template_id']??0),$this->userId());$_SESSION['flash_success']='Modèle dupliqué.';$this->redirect('/administration/axiom/document-designer?module_id='.$m.'&template_id='.$id);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/document-designer?module_id='.$m); }
    public function archiveDocumentTemplate(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);try{(new StudioDocumentService())->archive((int)($_POST['template_id']??0),$this->userId());$_SESSION['flash_success']='Modèle archivé.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/document-designer?module_id='.$m); }
    public function restoreDocumentTemplateVersion(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$id=(int)($_POST['template_id']??0);try{(new StudioDocumentService())->restoreVersion($id,(int)($_POST['version_id']??0),$this->userId());$_SESSION['flash_success']='Version restaurée dans un nouveau brouillon.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/document-designer?module_id='.$m.'&template_id='.$id); }
    public function generateDocumentTemplate(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$id=(int)($_POST['template_id']??0);try{$data=json_decode((string)($_POST['data_json']??'{}'),true,512,JSON_THROW_ON_ERROR);(new StudioDocumentService())->render($id,is_array($data)?$data:[],$this->userId(),true);$_SESSION['flash_success']='Document généré et inscrit au registre.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/document-designer?module_id='.$m.'&template_id='.$id); }

    private function userId(): ?int
    {
        $id = (int)($_SESSION['user']['id'] ?? 0);
        return $id > 0 ? $id : null;
    }

    private function requireStudioAccess(): void
    {
        Auth::requireLogin();
        Permission::requireAny('updates.view', 'backups.view', 'administration.permissions.view', 'utilisateurs.view');
    }

    private function countRows(string $table): int
    {
        try {
            if (!preg_match('/^[a-z0-9_]+$/i', $table)) {
                return 0;
            }
            return (int)Database::connection()->query('SELECT COUNT(*) FROM `' . $table . '`')->fetchColumn();
        } catch (Throwable) {
            return 0;
        }
    }

    public function reportDesigner(): void
    {
        $this->requireStudioAccess();$s=new StudioReportService();$moduleId=(int)($_GET['module_id']??0);$reportId=(int)($_GET['report_id']??0);$modules=$s->modules();if($moduleId<=0&&$modules)$moduleId=(int)$modules[0]['id'];$reports=$moduleId?$s->reports($moduleId):[];if($reportId<=0&&$reports)$reportId=(int)$reports[0]['id'];$report=$reportId?$s->report($reportId):null;$entities=$moduleId?$s->entities($moduleId):[];$entityId=(int)($_GET['entity_id']??($report['entity_id']??($entities[0]['id']??0)));$fields=$entityId?$s->fields($entityId):[];$preview=$reportId?$s->preview($reportId):['columns'=>[],'rows'=>[]];$this->view('axiom_studio/report_designer',['pageTitle'=>'Report Designer — AXIOM Studio','modules'=>$modules,'moduleId'=>$moduleId,'reports'=>$reports,'report'=>$report,'entities'=>$entities,'entityId'=>$entityId,'fields'=>$fields,'preview'=>$preview]);
    }
    public function saveReport(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);try{$id=(new StudioReportService())->save($m,$_POST,$this->userId());$_SESSION['flash_success']='Rapport enregistré.';$this->redirect('/administration/axiom/report-designer?module_id='.$m.'&report_id='.$id);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/report-designer?module_id='.$m); }
    public function publishReport(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$id=(int)($_POST['report_id']??0);try{(new StudioReportService())->publish($id,$this->userId());$_SESSION['flash_success']='Rapport publié.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/report-designer?module_id='.$m.'&report_id='.$id); }
    public function archiveReport(): void { $this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);try{(new StudioReportService())->archive((int)($_POST['report_id']??0),$this->userId());$_SESSION['flash_success']='Rapport archivé.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/report-designer?module_id='.$m); }
    public function exportReportCsv(): void { $this->requireStudioAccess();$id=(int)($_GET['report_id']??0);$p=(new StudioReportService())->preview($id);$name='rapport_'.$id.'.csv';header('Content-Type: text/csv; charset=UTF-8');header('Content-Disposition: attachment; filename="'.$name.'"');$o=fopen('php://output','wb');fwrite($o,"\xEF\xBB\xBF");fputcsv($o,array_map(fn($c)=>$c['name'],$p['columns']),';');foreach($p['rows'] as $r)fputcsv($o,array_values($r),';');fclose($o);exit; }


    public function apiBuilder(): void
    {
        $this->requireStudioAccess();
        $service = new StudioApiService();
        $moduleId = (int)($_GET['module_id'] ?? 0);
        $definitionId = (int)($_GET['definition_id'] ?? 0);
        $modules = $service->modules();
        if ($moduleId <= 0 && $modules) { $moduleId = (int)$modules[0]['id']; }
        $definitions = $moduleId > 0 ? $service->definitions($moduleId) : [];
        if ($definitionId <= 0 && $definitions) { $definitionId = (int)$definitions[0]['id']; }
        $definition = $definitionId > 0 ? $service->definition($definitionId) : null;
        $this->view('axiom_studio/api_builder', [
            'pageTitle' => 'API Builder — AXIOM Studio',
            'modules' => $modules,
            'moduleId' => $moduleId,
            'definitions' => $definitions,
            'definition' => $definition,
            'entities' => $moduleId > 0 ? $service->entities($moduleId) : [],
            'keys' => $definition ? $service->keys((int)$definition['id']) : [],
            'logs' => $definition ? $service->logs((int)$definition['id']) : [],
            'openApi' => $definition ? $service->openApi((int)$definition['id']) : null,
            'plainToken' => $_SESSION['axiom_api_plain_token'] ?? null,
        ]);
        unset($_SESSION['axiom_api_plain_token']);
    }

    public function saveApiDefinition(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);
        $moduleId=(int)($_POST['module_id']??0);
        try{$id=(new StudioApiService())->save($moduleId,$_POST,$this->userId());$_SESSION['flash_success']='Définition API enregistrée.';$this->redirect('/administration/axiom/api-builder?module_id='.$moduleId.'&definition_id='.$id);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/api-builder?module_id='.$moduleId);
    }

    public function publishApiDefinition(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);$moduleId=(int)($_POST['module_id']??0);$id=(int)($_POST['definition_id']??0);
        try{(new StudioApiService())->publish($id,$this->userId());$_SESSION['flash_success']='API publiée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/api-builder?module_id='.$moduleId.'&definition_id='.$id);
    }

    public function archiveApiDefinition(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);$moduleId=(int)($_POST['module_id']??0);
        try{(new StudioApiService())->archive((int)($_POST['definition_id']??0),$this->userId());$_SESSION['flash_success']='API archivée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/api-builder?module_id='.$moduleId);
    }

    public function createApiKey(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);$moduleId=(int)($_POST['module_id']??0);$id=(int)($_POST['definition_id']??0);
        try{$_SESSION['axiom_api_plain_token']=(new StudioApiService())->createKey($id,(string)($_POST['label']??''),$_POST['expires_at']??null,$this->userId());$_SESSION['flash_success']='Clé créée. Copiez-la maintenant : elle ne sera plus affichée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/api-builder?module_id='.$moduleId.'&definition_id='.$id);
    }

    public function revokeApiKey(): void
    {
        $this->requireStudioAccess(); Csrf::verify($_POST['_csrf'] ?? null);$moduleId=(int)($_POST['module_id']??0);$definitionId=(int)($_POST['definition_id']??0);
        try{(new StudioApiService())->revokeKey((int)($_POST['key_id']??0));$_SESSION['flash_success']='Clé révoquée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}
        $this->redirect('/administration/axiom/api-builder?module_id='.$moduleId.'&definition_id='.$definitionId);
    }

    public function apiOpenApi(): void
    {
        $this->requireStudioAccess();$id=(int)($_GET['definition_id']??0);header('Content-Type: application/json; charset=UTF-8');echo json_encode((new StudioApiService())->openApi($id),JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);exit;
    }


    private function directorySize(string $directory): int
    {
        if (!is_dir($directory)) {
            return 0;
        }

        $size = 0;
        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS)
        );

        foreach ($iterator as $item) {
            if ($item->isFile()) {
                $size += $item->getSize();
            }
        }

        return $size;
    }

    public function ruleBuilder(): void
    {
        $this->requireStudioAccess();$service=new StudioRuleService();$moduleId=(int)($_GET['module_id']??0);$ruleId=(int)($_GET['rule_id']??0);$modules=$service->modules();if($moduleId<=0&&$modules)$moduleId=(int)$modules[0]['id'];$rules=$moduleId?$service->rules($moduleId):[];if($ruleId<=0&&$rules)$ruleId=(int)$rules[0]['id'];$rule=$ruleId?$service->rule($ruleId):null;if($rule&&(int)$rule['module_id']!==$moduleId)$rule=null;$entityId=(int)($rule['entity_id']??($_GET['entity_id']??0));$simulation=$_SESSION['axiom_rule_simulation']??null;unset($_SESSION['axiom_rule_simulation']);
        $this->view('axiom_studio/rule_builder',['pageTitle'=>'Rule Builder — AXIOM Studio','modules'=>$modules,'moduleId'=>$moduleId,'rules'=>$rules,'rule'=>$rule,'entities'=>$moduleId?$service->entities($moduleId):[],'fields'=>$entityId?$service->fields($entityId):[],'conditions'=>$rule?$service->conditions($ruleId):[],'actions'=>$rule?$service->actions($ruleId):[],'logs'=>$rule?$service->logs($ruleId):[],'triggers'=>$service->triggers(),'operators'=>$service->operators(),'actionTypes'=>$service->actionTypes(),'simulation'=>$simulation]);
    }
    public function saveRule(): void{$this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);try{$id=(new StudioRuleService())->saveRule($m,$_POST,$this->userId());$_SESSION['flash_success']='Règle enregistrée.';$this->redirect('/administration/axiom/rule-builder?module_id='.$m.'&rule_id='.$id);return;}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/rule-builder?module_id='.$m);}
    public function addRuleCondition(): void{$this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$r=(int)($_POST['rule_id']??0);try{(new StudioRuleService())->addCondition($r,$_POST,$this->userId());$_SESSION['flash_success']='Condition ajoutée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/rule-builder?module_id='.$m.'&rule_id='.$r);}
    public function addRuleAction(): void{$this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$r=(int)($_POST['rule_id']??0);try{(new StudioRuleService())->addAction($r,$_POST,$this->userId());$_SESSION['flash_success']='Action ajoutée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/rule-builder?module_id='.$m.'&rule_id='.$r);}
    public function publishRule(): void{$this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$r=(int)($_POST['rule_id']??0);try{(new StudioRuleService())->publish($r,$this->userId());$_SESSION['flash_success']='Règle publiée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/rule-builder?module_id='.$m.'&rule_id='.$r);}
    public function archiveRuleItem(): void{$this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$r=(int)($_POST['rule_id']??0);$type=(string)($_POST['object_type']??'');try{(new StudioRuleService())->archiveItem($type,(int)($_POST['object_id']??0),$this->userId());$_SESSION['flash_success']='Élément archivé.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$url='/administration/axiom/rule-builder?module_id='.$m;if($type!=='rule')$url.='&rule_id='.$r;$this->redirect($url);}
    public function simulateRule(): void{$this->requireStudioAccess();Csrf::verify($_POST['_csrf']??null);$m=(int)($_POST['module_id']??0);$r=(int)($_POST['rule_id']??0);try{$record=json_decode((string)($_POST['record_json']??'{}'),true,512,JSON_THROW_ON_ERROR);if(!is_array($record))throw new \InvalidArgumentException('Le JSON de test doit représenter un objet.');$_SESSION['axiom_rule_simulation']=(new StudioRuleService())->executeManual($r,$record,$this->userId());$_SESSION['flash_success']='Simulation terminée et journalisée.';}catch(\Throwable $e){$_SESSION['flash_error']=$e->getMessage();}$this->redirect('/administration/axiom/rule-builder?module_id='.$m.'&rule_id='.$r);}

}
