<?php


namespace App\Models;

use CodeIgniter\Model;
use Config\Database;
class EventsModel extends Model
{
    protected $table = 'reader_config'; // table bidon
    protected $primaryKey = 'con_id';

    protected $allowedFields = [
        'name',
        'location',
        'date',
    ];

    // ---------------------------------------------------------
    // Lire un événement selon l'ID
    // ---------------------------------------------------------
    public function getEvent(int $id): ?array
    {
        return $this->asArray()->find($id);
    }
    public function getLinkedData(int $id): array
    {
        // 1) Lire la config dans la DB par défaut
        $config = $this->asArray()->find($id);

        if (!$config) {
            return [];
        }

        // 2) Connexion à la base MS1Timing
        $db = \Config\Database::connect('ms1timing');

        // 3) Lire Course
        $course = $db->table('courses')
            ->where('cou_id', $config['cou_id'])
            ->get()
            ->getRowArray();

        // 4) Lire Event
        $event = $db->table('evenements')
            ->where('eve_id', $config['eve_id'])
            ->get()
            ->getRowArray();

        return [
            'config' => $config,
            'course' => $course,
            'event'  => $event,
        ];
    }

    public function getLinkedDatatimingpoint(int $id): array
    {
        $db = \Config\Database::connect();

        // 1) Lire les timing points pour cette course
        $timingpoints = $db->table('reader_config_timingpoint')
            ->where('con_id', $id)
            ->orderBy('tp_trie', 'ASC')
            ->get()
            ->getResultArray();

        // Si aucun TP, on retourne vide
        if (empty($timingpoints)) {
            return ['timingpoint' => []];
        }

        // 2) Préparer liste des tp_id
        $tpIds = array_column($timingpoints, 'tp_id');

        // 3) Construire nom de la table dynamic
        $detailTable = "resultv2_{$id}_detail";

        // 4) UNE SEULE requête SQL pour compter par TP (optimisation majeure)
        $counts = $db->table($detailTable)
            ->select('tp_id, COUNT(*) as total')
            ->whereIn('tp_id', $tpIds)
            ->groupBy('tp_id')
            ->get()
            ->getResultArray();

        // 5) Convertir le résultat en tableau associatif: [tp_id => count]
        $countMap = [];
        foreach ($counts as $row) {
            $countMap[$row['tp_id']] = (int) $row['total'];
        }

        // 6) Injecter le count dans chaque timing point
        foreach ($timingpoints as &$tp) {
            $tpId = $tp['tp_id'];
            $tp['lecture_count'] = $countMap[$tpId] ?? 0;
        }

        return [
            'timingpoint' => $timingpoints
        ];
    }

    public function getProcessStatus($con_id)
    {
        $table = "resultv2_{$con_id}_lecture";

        $row = $this->db->query("SELECT process_status FROM `$table` LIMIT 1")->getRow();

        return $row ? $row->process_status : null;
    }







    public function getStatsByEventName(string $eventName): array
    {
        $db = \Config\Database::connect(); // DB par défaut

        $results = $db->table('reader_lectures')
            ->select('chrinfo_location, COUNT(*) AS total, MIN(chrinfo_time) AS start_time, MAX(chrinfo_time) AS end_time')
             ->where('chrinfo_event_name', $eventName)
            ->where('chrinfo_type_transaction !=', 'NEW LOCATION')
            ->groupBy('chrinfo_location')
            ->get()
            ->getResultArray();

        // Transformer en tableau avec clé 1,2,3...
        $final = [];
        $i = 1;

        foreach ($results as $row) {
            $final[$i] = [
                'location'    => $row['chrinfo_location'],
                'count'       => (int)$row['total'],
                'start_time'  => $row['start_time'],
                'end_time'    => $row['end_time'],
                'icon' => 'lucide--eye',
                'bg_color' => '#F7B6A8'
            ];
            $i++;
        }

        return $final;
    }
    public function getEventList(): array
    {
        // 1) Lire tous les événements
        $events = $this->asArray()

            ->findAll();

        $final = [];

        // 2) Ajouter les données liées pour chaque ligne
        foreach ($events as $event) {

            $linked = $this->getLinkedData($event['con_id']);

            $final[] = [
                'config' => $linked['config'],
                'course' => $linked['course'],
                'event'  => $linked['event'],
            ];
        }

        // 3) Trier par eve_date_debut DESC (du plus récent au plus ancien)
        usort($final, function($a, $b) {
            return strcmp($b['event']['eve_date_debut'], $a['event']['eve_date_debut']);
        });

        return $final;
    }

    /**
     * Duplique les tables de résultats sur la connexion ms1timing_slave
     * à partir des tables *_template vers *_{$courseId}.
     *
     * @param int $courseId  ex: 2152
     * @return array         liste des statuts par table
     */

    public function duplicateResultTables(int $courseId): array
    {
        // Connexion à la base ms1timing_slave (déjà définie dans Database.php)
        $db = \Config\Database::connect();

        // Suffixes des tables
        $suffixes = [
            'classement',
            'detail',
            'log',
            'pause',
            'lecture',
            'lecture_statut'
        ];

        $results = [];

        foreach ($suffixes as $suffix) {

            // Nouveau format demandé
            $templateTable = "resultv2_template_{$suffix}";
            $newTable      = "resultv2_{$courseId}_{$suffix}";

            // Vérifier que la table template existe
            if (! $db->tableExists($templateTable)) {
                $results[] = [
                    'table'  => $newTable,
                    'status' => 'template_missing',
                    'message'=> "La table template {$templateTable} n’existe pas.",
                ];
                continue;
            }

            // Si la nouvelle table existe déjà, on ne la touche pas
            if ($db->tableExists($newTable)) {
                $results[] = [
                    'table'  => $newTable,
                    'status' => 'exists',
                    'message'=> "La table {$newTable} existe déjà. Aucune action.",
                ];
                continue;
            }

            // Création + remplissage dans une transaction
            $db->transStart();

            // CREATE TABLE nouveau LIKE template
            $db->query(
                "CREATE TABLE `{$newTable}` LIKE `{$templateTable}`"
            );

            // Cas particulier pour la table lecture : on met directement les bonnes valeurs initiales
            if ($suffix === 'lecture') {
                $db->query("
                INSERT INTO `{$newTable}` (
                    id,
                    last_processed_read_id,
                    config_hash,
                    needs_rebuild,
                    process_status,
                    backup_flag,
                    last_rebuild_ts,
                    last_backup_ts,
                    moteur_version,
                    created_at,
                    updated_at
                ) VALUES (
                    1,
                    0,
                    '',
                    0,
                    'IDLE',
                    0,
                    NULL,
                    NULL,
                    '1.0',
                    NOW(),
                    NOW()
                )
            ");
            } else {
                // INSERT INTO new SELECT * FROM template (comportement existant)
                $db->query(
                    "INSERT INTO `{$newTable}` SELECT * FROM `{$templateTable}`"
                );
            }

            $db->transComplete();

            if ($db->transStatus() === false) {
                $results[] = [
                    'table'  => $newTable,
                    'status' => 'error',
                    'message'=> "Erreur lors de la duplication de {$newTable}.",
                ];
            } else {
                $results[] = [
                    'table'  => $newTable,
                    'status' => 'created',
                    'message'=> "Table {$newTable} créée et remplie à partir de {$templateTable}.",
                ];
            }
        }

        return $results;
    }


    /**
     * Récupère les timingpoints + toutes les configurations associées
     * à partir de la table reader_config_detail.
     *
     * @param int $id  ID du contrôleur (con_id)
     * @return array   Tableau final des timingpoints enrichis
     */
    public function getLinkedDatatimingpointWithConfig(int $id)
    {
        //----------------------------------------------------------------------
        // 1. Récupération des timingpoints existants (déjà fonctionnel chez toi)
        //----------------------------------------------------------------------
        $data = $this->getLinkedDatatimingpoint($id);

        // Sécurité : si aucun timingpoint, on retourne tout de suite
        if (!isset($data['timingpoint']) || empty($data['timingpoint'])) {
            return $data;
        }

        //----------------------------------------------------------------------
        // 2. Boucle sur chaque timingpoint (un tp_id à la fois)
        //----------------------------------------------------------------------
        foreach ($data['timingpoint'] as $index => $tp) {

            $tp_id = $tp['tp_id'];

            //------------------------------------------------------------------
            // 3. Aller chercher toutes les lignes reader_config_detail
            //    où det_ref1_id = tp_id
            //------------------------------------------------------------------
            $builder = $this->db->table('reader_config_detail');
            $builder->where('det_ref1_id', $tp_id);
            $builder->orderBy('det_trie', 'ASC');

            $rows = $builder->get()->getResultArray();

            //------------------------------------------------------------------
            // 4. Aucune config → on continue au suivant
            //------------------------------------------------------------------
            if (empty($rows)) {
                continue;
            }

            //------------------------------------------------------------------
            // 5. Préparation des conteneurs de regroupement
            //------------------------------------------------------------------
            $configSets = [];

            //------------------------------------------------------------------
            // 6. Boucle à travers chaque config trouvée
            //------------------------------------------------------------------
            foreach ($rows as $row) {

                //--------------------------------------------------------------
                // 6.1 Extraction du groupe (ex: configs-tp, configs-tp-interval)
                //     → conversion en identifiant propre pour le tableau final
                //--------------------------------------------------------------
                $groupName = !empty($row['det_groupe'])
                    ? str_replace('-', '_', $row['det_groupe'])
                    : 'configs_generic';   // fallback, jamais vide

                //--------------------------------------------------------------
                // 6.2 La clef interne (ex: clef_controleur)
                //--------------------------------------------------------------
                $clef = $row['det_clef'];

                if (empty($clef)) {
                    // Si jamais c'est vide, on ignore cette ligne
                    continue;
                }

                //--------------------------------------------------------------
                // 6.3 Préparer la structure si elle n'existe pas encore
                //--------------------------------------------------------------
                if (!isset($configSets[$groupName])) {
                    $configSets[$groupName] = [];
                }
                if (!isset($configSets[$groupName][$clef])) {
                    $configSets[$groupName][$clef] = [];
                }

                //--------------------------------------------------------------
                // 6.4 Ajouter la ligne de configuration
                //--------------------------------------------------------------
                $configSets[$groupName][$clef][] = [
                    'value1' => $row['det_value1'],
                    'value2' => $row['det_value2'],
                    'value3' => $row['det_value3'],
                ];
            }

            //------------------------------------------------------------------
            // 7. Injection dans le timingpoint final
            //------------------------------------------------------------------
            $data['timingpoint'][$index] = array_merge(
                $data['timingpoint'][$index],
                $configSets
            );
        }

        //----------------------------------------------------------------------
        // 8. Retour final
        //----------------------------------------------------------------------
        return $data;
    }

    public function getcourseConfig(int $id)
    {





            //------------------------------------------------------------------
            $builder = $this->db->table('reader_config_detail');
            $builder->where('det_ref1_id', $id);
            $builder->where('det_type', 2);
            $builder->orderBy('det_trie', 'ASC');

            $rows = $builder->get()->getResultArray();

        //------------------------------------------------------------------
        // 5. Préparation des conteneurs de regroupement
        //------------------------------------------------------------------
        $configSets = [];

        //------------------------------------------------------------------
        // 6. Boucle à travers chaque config trouvée
        //------------------------------------------------------------------
        foreach ($rows as $row) {

            //--------------------------------------------------------------
            // 6.1 Extraction du groupe (ex: configs-tp, configs-tp-interval)
            //     → conversion en identifiant propre pour le tableau final
            //--------------------------------------------------------------
            $groupName = !empty($row['det_groupe'])
                ? str_replace('-', '_', $row['det_groupe'])
                : 'configs_generic';   // fallback, jamais vide

            //--------------------------------------------------------------
            // 6.2 La clef interne (ex: clef_controleur)
            //--------------------------------------------------------------
            $clef = $row['det_clef'];

            if (empty($clef)) {
                // Si jamais c'est vide, on ignore cette ligne
                continue;
            }

            //--------------------------------------------------------------
            // 6.3 Préparer la structure si elle n'existe pas encore
            //--------------------------------------------------------------
            if (!isset($configSets[$groupName])) {
                $configSets[$groupName] = [];
            }
            if (!isset($configSets[$groupName][$clef])) {
                $configSets[$groupName][$clef] = [];
            }

            //--------------------------------------------------------------
            // 6.4 Ajouter la ligne de configuration
            //--------------------------------------------------------------
          $output=$row['det_value1'];
            if($row['det_type_output']!='')
                $output=format_output($row['det_value1'], $row['det_type_output']);

            $configSets[$groupName][$clef][] = [
                'value1' => $row['det_value1'],
                'value2' => $row['det_value2'],
                'value3' => $row['det_value3'],
                'output' => $output,

            ];
        }




                //--------------------------------------------------------------

        //----------------------------------------------------------------------
        // 8. Retour final
        //----------------------------------------------------------------------
        return  $configSets;
    }
    public function resetCourse($con_id)
    {
        $lectureTable = "resultv2_{$con_id}_lecture";
        $detailTable  = "resultv2_{$con_id}_detail";

        // -------------------------------------------------
        // 1) Demander la pause (PAUSE_REQUEST)
        // -------------------------------------------------
        $this->db->query("UPDATE `$lectureTable` SET process_status = 'PAUSE_REQUEST'");

        // -------------------------------------------------
        // 2) Attendre que Python applique PAUSE
        // -------------------------------------------------
        $timeoutSeconds = 20 * 60;     // 20 minutes
        $waitInterval   = 500000;      // 0.5 seconde
        $attempts       = ($timeoutSeconds * 1000000) / $waitInterval;

        $isPaused = false;

        for ($i = 0; $i < $attempts; $i++) {

            $row = $this->db->query("SELECT process_status FROM `$lectureTable` LIMIT 1")->getRow();

            if ($row && strtoupper($row->process_status) === 'PAUSE') {
                $isPaused = true;
                break;
            }

            // Attendre 0.5 sec avant de rechecker
            usleep($waitInterval);
        }

        if (!$isPaused) {
            return "ERREUR : Impossible d'obtenir PAUSE (timeout). Base NON modifiée.";
        }

        // -------------------------------------------------
        // 3) TRUNCATE de la table detail (sécurisé)
        // -------------------------------------------------
        $this->db->query("TRUNCATE TABLE `$detailTable`");

        // -------------------------------------------------
        // 4) Remettre last_processed_read_id à 0
        // -------------------------------------------------
        $this->db->query("
        UPDATE `$lectureTable`
        SET last_processed_read_id = 0
    ");

        // -------------------------------------------------
        // 5) Remettre la course en IDLE pour que Python puisse repartir
        // -------------------------------------------------
        $this->db->query("UPDATE `$lectureTable` SET process_status = 'IDLE'");

        return "OK : Course réinitialisée.";
    }



}
