<?php
declare(strict_types=1);

namespace App\Services;

use App\Core\Database;
use InvalidArgumentException;
use PDO;
use RuntimeException;

final class WorkflowEngineService
{
    public function start(int $workflowId,string $subjectType,int $subjectId,?int $userId,array $context=[]): int
    {
        $studio=new StudioWorkflowService(); $workflow=$studio->workflow($workflowId);
        if(!$workflow || ($workflow['status']??'')!=='published') throw new RuntimeException('Le workflow doit être publié avant exécution.');
        $start=null; foreach($studio->nodes($workflowId) as $node){if($node['node_type']==='start'){$start=$node;break;}}
        if(!$start) throw new RuntimeException('Aucune étape de départ disponible.');
        $pdo=Database::connection(); $pdo->beginTransaction();
        try{
            $q=$pdo->prepare("INSERT INTO axiom_workflow_instances(workflow_id,workflow_version,subject_type,subject_id,current_node_id,status,context_json,started_by) VALUES(:w,:v,:t,:s,:n,'running',:j,:u)");
            $q->execute(['w'=>$workflowId,'v'=>(int)$workflow['current_version'],'t'=>$subjectType,'s'=>$subjectId,'n'=>(int)$start['id'],'j'=>json_encode($context,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),'u'=>$userId]);
            $id=(int)$pdo->lastInsertId(); $this->history($id,null,(int)$start['id'],'started','Instance démarrée.',$userId); $pdo->commit(); return $id;
        }catch(\Throwable $e){if($pdo->inTransaction())$pdo->rollBack();throw $e;}
    }

    public function transition(int $instanceId,int $transitionId,?int $userId,?string $comment=null): void
    {
        $pdo=Database::connection(); $q=$pdo->prepare("SELECT * FROM axiom_workflow_instances WHERE id=:id AND status='running'");$q->execute(['id'=>$instanceId]);$instance=$q->fetch(PDO::FETCH_ASSOC);
        if(!$instance)throw new InvalidArgumentException('Instance active introuvable.');
        $q=$pdo->prepare("SELECT t.*,n.node_type target_type,n.configuration_json FROM axiom_workflow_transitions t JOIN axiom_workflow_nodes n ON n.id=t.target_node_id WHERE t.id=:id AND t.workflow_id=:w AND t.source_node_id=:s AND t.archived_at IS NULL");
        $q->execute(['id'=>$transitionId,'w'=>$instance['workflow_id'],'s'=>$instance['current_node_id']]);$transition=$q->fetch(PDO::FETCH_ASSOC);
        if(!$transition)throw new InvalidArgumentException('Transition non autorisée depuis l’étape courante.');
        $status=$transition['target_type']==='end'?'completed':'running';
        $pdo->beginTransaction();try{
            $pdo->prepare("UPDATE axiom_workflow_instances SET current_node_id=:n,status=:st,completed_at=IF(:st='completed',CURRENT_TIMESTAMP,NULL),updated_at=CURRENT_TIMESTAMP WHERE id=:id")->execute(['n'=>$transition['target_node_id'],'st'=>$status,'id'=>$instanceId]);
            $this->history($instanceId,(int)$instance['current_node_id'],(int)$transition['target_node_id'],'transition',$comment,$userId);
            if(in_array($transition['target_type'],['approval','assignment'],true)){
                $cfg=json_decode((string)$transition['configuration_json'],true)?:[];
                $pdo->prepare("INSERT INTO axiom_workflow_tasks(instance_id,node_id,title,status,assignee_type,assignee_value,created_by) VALUES(:i,:n,:t,'open',:at,:av,:u)")->execute(['i'=>$instanceId,'n'=>$transition['target_node_id'],'t'=>'Tâche workflow','at'=>$cfg['assignee_type']??null,'av'=>$cfg['assignee_value']??null,'u'=>$userId]);
            }
            $pdo->commit();
        }catch(\Throwable $e){if($pdo->inTransaction())$pdo->rollBack();throw $e;}
    }

    private function history(int $instanceId,?int $from,int $to,string $action,?string $comment,?int $userId): void
    {
        Database::connection()->prepare("INSERT INTO axiom_workflow_history(instance_id,from_node_id,to_node_id,action,comment,performed_by) VALUES(:i,:f,:t,:a,:c,:u)")->execute(['i'=>$instanceId,'f'=>$from,'t'=>$to,'a'=>$action,'c'=>$comment,'u'=>$userId]);
    }
}
