<?php

/**
 * Migration des secteurs (ope_sectors) et données associées
 *
 * Gère la migration des secteurs avec leurs adresses, associations
 * utilisateurs-secteurs, et passages. Utilise PassageMigrator pour les passages.
 */
class SectorMigrator
{
    private PDO $sourceDb;
    private PDO $targetDb;
    private MigrationLogger $logger;
    private PassageMigrator $passageMigrator;
    private array $sectorMapping = [];

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

    /**
     * Migre un secteur dans le contexte d'une opération
     *
     * @param int $oldOperationId ID ancienne opération
     * @param int $newOperationId ID nouvelle opération
     * @param int $oldSectorId ID ancien secteur
     * @param array $userMapping Mapping oldUserId => newOpeUserId
     * @return array|null ['id' => int, 'name' => string, 'users' => int, 'passages' => int] ou null en cas d'erreur
     */
    public function migrateSector(
        int $oldOperationId,
        int $newOperationId,
        int $oldSectorId,
        array $userMapping
    ): ?array {
        $this->logger->info("  📍 Migration secteur ID: {$oldSectorId}");

        try {
            // 1. Récupérer le secteur source
            $stmt = $this->sourceDb->prepare("
                SELECT * FROM sectors WHERE rowid = :id
            ");
            $stmt->execute([':id' => $oldSectorId]);
            $sector = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$sector) {
                $this->logger->warning("  Secteur {$oldSectorId} non trouvé");
                return null;
            }

            // 2. Créer dans ope_sectors
            $newOpeSectorId = $this->createOpeSector($sector, $newOperationId);

            if (!$newOpeSectorId) {
                return null;
            }

            // 3. Mapper "operationId_sectorId" → newOpeSectorId
            $mappingKey = "{$oldOperationId}_{$oldSectorId}";
            $this->sectorMapping[$mappingKey] = $newOpeSectorId;

            $this->logger->success("  ✓ Secteur créé avec ID: {$newOpeSectorId}");

            // 4. Migrer sectors_adresses
            $this->migrateSectorAddresses($oldSectorId, $newOpeSectorId);

            // 5. Migrer ope_users_sectors
            $usersCount = $this->migrateUsersSectors($oldOperationId, $newOperationId, $oldSectorId, $newOpeSectorId, $userMapping);

            // 6. Migrer ope_pass
            $passagesCount = $this->passageMigrator->migratePassages(
                $oldOperationId,
                $newOperationId,
                $oldSectorId,
                $newOpeSectorId,
                $userMapping
            );

            return [
                'id' => $newOpeSectorId,
                'name' => $sector['libelle'],
                'users' => $usersCount,
                'passages' => $passagesCount
            ];

        } catch (Exception $e) {
            $this->logger->error("  ❌ Erreur migration secteur {$oldSectorId}: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Crée un secteur dans ope_sectors
     *
     * @param array $sector Données du secteur
     * @param int $newOperationId ID nouvelle opération
     * @return int|null ID du nouveau secteur ou null en cas d'erreur
     */
    private function createOpeSector(array $sector, int $newOperationId): ?int
    {
        try {
            $stmt = $this->targetDb->prepare("
                INSERT INTO ope_sectors (
                    fk_operation, libelle, sector, color,
                    created_at, fk_user_creat, updated_at, fk_user_modif, chk_active
                ) VALUES (
                    :fk_operation, :libelle, :sector, :color,
                    :created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active
                )
            ");

            $stmt->execute([
                ':fk_operation' => $newOperationId,
                ':libelle' => $sector['libelle'],
                ':sector' => $sector['sector'],
                ':color' => $sector['color'],
                ':created_at' => $sector['date_creat'],
                ':fk_user_creat' => $sector['fk_user_creat'] ?? 0,
                ':updated_at' => $sector['date_modif'],
                ':fk_user_modif' => $sector['fk_user_modif'] ?? 0,
                ':chk_active' => $sector['active']
            ]);

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

        } catch (Exception $e) {
            $this->logger->error("  ❌ Erreur création secteur: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Migre les adresses d'un secteur
     *
     * @param int $oldSectorId ID ancien secteur
     * @param int $newOpeSectorId ID nouveau ope_sectors
     * @return int Nombre d'adresses migrées
     */
    private function migrateSectorAddresses(int $oldSectorId, int $newOpeSectorId): int
    {
        $stmt = $this->sourceDb->prepare("
            SELECT * FROM sectors_adresses WHERE fk_sector = :sector_id
        ");
        $stmt->execute([':sector_id' => $oldSectorId]);
        $addresses = $stmt->fetchAll(PDO::FETCH_ASSOC);

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

        $count = 0;
        foreach ($addresses as $address) {
            $stmt = $this->targetDb->prepare("
                INSERT INTO sectors_adresses (
                    fk_adresse, fk_sector, numero, rue_bis, rue, cp, ville,
                    gps_lat, gps_lng
                ) VALUES (
                    :fk_adresse, :fk_sector, :numero, :rue_bis, :rue, :cp, :ville,
                    :gps_lat, :gps_lng
                )
            ");

            $stmt->execute([
                ':fk_adresse' => $address['fk_adresse'], // Garde la valeur telle quelle
                ':fk_sector' => $newOpeSectorId,
                ':numero' => $address['numero'],
                ':rue_bis' => $address['rue_bis'],
                ':rue' => $address['rue'],
                ':cp' => $address['cp'],
                ':ville' => $address['ville'],
                ':gps_lat' => $address['gps_lat'],
                ':gps_lng' => $address['gps_lng']
            ]);

            $count++;
        }

        $this->logger->success("  ✓ {$count} adresse(s) migrée(s)");

        return $count;
    }

    /**
     * Migre les associations utilisateurs-secteurs
     *
     * @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 d'associations migrées
     */
    private function migrateUsersSectors(
        int $oldOperationId,
        int $newOperationId,
        int $oldSectorId,
        int $newOpeSectorId,
        array $userMapping
    ): int {
        $stmt = $this->sourceDb->prepare("
            SELECT * FROM ope_users_sectors
            WHERE fk_operation = :operation_id
            AND fk_sector = :sector_id
            AND active = 1
        ");
        $stmt->execute([
            ':operation_id' => $oldOperationId,
            ':sector_id' => $oldSectorId
        ]);
        $usersSectors = $stmt->fetchAll(PDO::FETCH_ASSOC);

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

        $count = 0;
        foreach ($usersSectors as $us) {
            // Vérifier que l'utilisateur existe dans le mapping
            // (le mapping sert juste à vérifier que l'user a été migré)
            if (!isset($userMapping[$us['fk_user']])) {
                $this->logger->warning("  ⚠ User {$us['fk_user']} non trouvé dans mapping");
                continue;
            }

            $stmt = $this->targetDb->prepare("
                INSERT INTO ope_users_sectors (
                    fk_operation, fk_user, fk_sector,
                    created_at, fk_user_creat, updated_at, fk_user_modif, chk_active
                ) VALUES (
                    :fk_operation, :fk_user, :fk_sector,
                    :created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active
                )
            ");

            $stmt->execute([
                ':fk_operation' => $newOperationId,
                ':fk_user' => $userMapping[$us['fk_user']], // ID de ope_users (mapping)
                ':fk_sector' => $newOpeSectorId,
                ':created_at' => date('Y-m-d H:i:s'),
                ':fk_user_creat' => 0,
                ':updated_at' => null,
                ':fk_user_modif' => null,
                ':chk_active' => $us['active']
            ]);

            $count++;
        }

        $this->logger->success("  ✓ {$count} association(s) user-secteur migrée(s)");

        return $count;
    }

    /**
     * Retourne le mapping des secteurs
     *
     * @return array "operationId_sectorId" => newOpeSectorId
     */
    public function getSectorMapping(): array
    {
        return $this->sectorMapping;
    }

    /**
     * Définit le mapping des secteurs (utile pour réutilisation)
     *
     * @param array $mapping "operationId_sectorId" => newOpeSectorId
     */
    public function setSectorMapping(array $mapping): void
    {
        $this->sectorMapping = $mapping;
    }
}
