<?php

/**
 * Migration des passages (ope_pass) et historiques (ope_pass_histo)
 *
 * Gère la migration des passages avec vérification du trio
 * (operation, user, sector) et migration des historiques associés
 */
class PassageMigrator
{
    private PDO $sourceDb;
    private PDO $targetDb;
    private MigrationLogger $logger;

    /**
     * Constructeur
     *
     * @param PDO $sourceDb Connexion source
     * @param PDO $targetDb Connexion cible
     * @param MigrationLogger $logger Logger
     */
    public function __construct(PDO $sourceDb, PDO $targetDb, MigrationLogger $logger)
    {
        $this->sourceDb = $sourceDb;
        $this->targetDb = $targetDb;
        $this->logger = $logger;
    }

    /**
     * Migre les passages d'un secteur dans une opération
     *
     * @param int $oldOperationId ID ancienne opération
     * @param int $newOperationId ID nouvelle opération
     * @param int $oldSectorId ID ancien secteur
     * @param int $newOpeSectorId ID nouveau ope_sectors
     * @param array $userMapping Mapping oldUserId => newOpeUserId
     * @return int Nombre de passages migrés
     */
    public function migratePassages(
        int $oldOperationId,
        int $newOperationId,
        int $oldSectorId,
        int $newOpeSectorId,
        array $userMapping
    ): int {
        $stmt = $this->sourceDb->prepare("
            SELECT * FROM ope_pass
            WHERE fk_operation = :operation_id
            AND fk_sector = :sector_id
        ");
        $stmt->execute([
            ':operation_id' => $oldOperationId,
            ':sector_id' => $oldSectorId
        ]);
        $passages = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if (empty($passages)) {
            return 0;
        }

        $count = 0;
        foreach ($passages as $passage) {
            // Vérifier que l'utilisateur a été migré
            if (!isset($userMapping[$passage['fk_user']])) {
                $this->logger->warning("  ⚠ Passage {$passage['rowid']}: User {$passage['fk_user']} non trouvé dans mapping");
                continue;
            }

            // Récupérer l'ID de ope_users depuis le mapping
            $newOpeUserId = $userMapping[$passage['fk_user']];

            // Vérifier que le trio (operation, user, sector) existe dans ope_users_sectors
            if (!$this->verifyUserSectorAssociation($newOperationId, $newOpeUserId, $newOpeSectorId)) {
                $this->logger->warning("  ⚠ Passage {$passage['rowid']}: Trio (op={$newOperationId}, user={$newOpeUserId}, sector={$newOpeSectorId}) inexistant");
                continue;
            }

            // Insérer le passage avec l'ID de ope_users
            $newPassId = $this->insertPassage($passage, $newOperationId, $newOpeSectorId, $newOpeUserId);

            if ($newPassId) {
                // Migrer l'historique du passage
                $this->migratePassageHisto($passage['rowid'], $newPassId, $userMapping);
                $count++;
            }
        }

        if ($count > 0) {
            $this->logger->success("  ✓ {$count} passage(s) migré(s)");
        }

        return $count;
    }

    /**
     * Vérifie qu'une association user-sector existe dans ope_users_sectors
     *
     * @param int $operationId ID opération
     * @param int $userId ID ope_users (mapping)
     * @param int $sectorId ID ope_sectors
     * @return bool True si l'association existe
     */
    private function verifyUserSectorAssociation(int $operationId, int $userId, int $sectorId): bool
    {
        $stmt = $this->targetDb->prepare("
            SELECT COUNT(*) FROM ope_users_sectors
            WHERE fk_operation = :operation_id
            AND fk_user = :user_id
            AND fk_sector = :sector_id
        ");
        $stmt->execute([
            ':operation_id' => $operationId,
            ':user_id' => $userId,
            ':sector_id' => $sectorId
        ]);

        return $stmt->fetchColumn() > 0;
    }

    /**
     * Insère un passage dans la nouvelle base
     *
     * @param array $passage Données du passage
     * @param int $newOperationId ID nouvelle opération
     * @param int $newOpeSectorId ID nouveau secteur
     * @param int $userId ID de ope_users (mapping)
     * @return int|null ID du nouveau passage ou null en cas d'erreur
     */
    private function insertPassage(
        array $passage,
        int $newOperationId,
        int $newOpeSectorId,
        int $userId
    ): ?int {
        try {
            $stmt = $this->targetDb->prepare("
                INSERT INTO ope_pass (
                    fk_operation, fk_sector, fk_user, fk_adresse,
                    passed_at, fk_type, numero, rue, rue_bis, ville,
                    fk_habitat, appt, niveau, residence,
                    gps_lat, gps_lng, encrypted_name, montant, fk_type_reglement,
                    remarque, nom_recu, encrypted_email, email_erreur, chk_email_sent,
                    encrypted_phone, docremis, date_repasser, nb_passages,
                    chk_gps_maj, chk_map_create, chk_mobile, chk_synchro,
                    chk_api_adresse, chk_maj_adresse, anomalie,
                    created_at, fk_user_creat, updated_at, fk_user_modif, chk_active
                ) VALUES (
                    :fk_operation, :fk_sector, :fk_user, :fk_adresse,
                    :passed_at, :fk_type, :numero, :rue, :rue_bis, :ville,
                    :fk_habitat, :appt, :niveau, :residence,
                    :gps_lat, :gps_lng, :encrypted_name, :montant, :fk_type_reglement,
                    :remarque, :nom_recu, :encrypted_email, :email_erreur, :chk_email_sent,
                    :encrypted_phone, :docremis, :date_repasser, :nb_passages,
                    :chk_gps_maj, :chk_map_create, :chk_mobile, :chk_synchro,
                    :chk_api_adresse, :chk_maj_adresse, :anomalie,
                    :created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active
                )
            ");

            // Chiffrer les données sensibles
            require_once dirname(__DIR__, 4) . '/src/Services/ApiService.php';

            $stmt->execute([
                ':fk_operation' => $newOperationId,
                ':fk_sector' => $newOpeSectorId,
                ':fk_user' => $userId, // ID de ope_users (mapping)
                ':fk_adresse' => $passage['fk_adresse'],
                ':passed_at' => $passage['date_eve'],
                ':fk_type' => $passage['fk_type'],
                ':numero' => $passage['numero'],
                ':rue' => $passage['rue'],
                ':rue_bis' => $passage['rue_bis'],
                ':ville' => $passage['ville'],
                ':fk_habitat' => $passage['fk_habitat'],
                ':appt' => $passage['appt'],
                ':niveau' => $passage['niveau'],
                ':residence' => $passage['lieudit'] ?? null,
                ':gps_lat' => $passage['gps_lat'],
                ':gps_lng' => $passage['gps_lng'],
                ':encrypted_name' => $passage['libelle'] ? ApiService::encryptData($passage['libelle']) : '', // Chiffrer avec IV aléatoire
                ':montant' => $passage['montant'],
                ':fk_type_reglement' => (!empty($passage['fk_type_reglement']) && $passage['fk_type_reglement'] > 0) ? $passage['fk_type_reglement'] : 4,
                ':remarque' => $passage['remarque'],
                ':nom_recu' => $passage['recu'] ?? null,
                ':encrypted_email' => $passage['email'] ? ApiService::encryptSearchableData($passage['email']) : null,
                ':email_erreur' => $passage['email_erreur'],
                ':chk_email_sent' => $passage['chk_email_sent'],
                ':encrypted_phone' => $passage['phone'] ? ApiService::encryptData($passage['phone']) : '',
                ':docremis' => $passage['docremis'],
                ':date_repasser' => $passage['date_repasser'],
                ':nb_passages' => ($passage['fk_type'] == 2) ? 0 : $passage['nb_passages'],
                ':chk_gps_maj' => $passage['chk_gps_maj'],
                ':chk_map_create' => $passage['chk_map_create'],
                ':chk_mobile' => $passage['chk_mobile'],
                ':chk_synchro' => $passage['chk_synchro'],
                ':chk_api_adresse' => $passage['chk_api_adresse'],
                ':chk_maj_adresse' => $passage['chk_maj_adresse'],
                ':anomalie' => $passage['anomalie'],
                ':created_at' => $passage['date_creat'],
                ':fk_user_creat' => $passage['fk_user_creat'] ?? 0,
                ':updated_at' => $passage['date_modif'],
                ':fk_user_modif' => $passage['fk_user_modif'] ?? 0,
                ':chk_active' => $passage['active']
            ]);

            return (int)$this->targetDb->lastInsertId();

        } catch (Exception $e) {
            $this->logger->error("  ❌ Erreur insertion passage {$passage['rowid']}: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Migre l'historique d'un passage
     *
     * @param int $oldPassId ID ancien passage
     * @param int $newPassId ID nouveau passage
     * @param array $userMapping Non utilisé (conservé pour compatibilité)
     * @return int Nombre d'entrées d'historique migrées
     */
    public function migratePassageHisto(int $oldPassId, int $newPassId, array $userMapping): int
    {
        $stmt = $this->sourceDb->prepare("
            SELECT * FROM ope_pass_histo WHERE fk_pass = :pass_id
        ");
        $stmt->execute([':pass_id' => $oldPassId]);
        $histos = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if (empty($histos)) {
            return 0;
        }

        $count = 0;
        foreach ($histos as $histo) {
            $stmt = $this->targetDb->prepare("
                INSERT INTO ope_pass_histo (
                    fk_pass, date_histo, sujet, remarque
                ) VALUES (
                    :fk_pass, :date_histo, :sujet, :remarque
                )
            ");

            $stmt->execute([
                ':fk_pass' => $newPassId,
                ':date_histo' => $histo['date_histo'],
                ':sujet' => $histo['sujet'],
                ':remarque' => $histo['remarque']
            ]);

            $count++;
        }

        return $count;
    }
}
