<?php
namespace GlpiPlugin\Wbstore;

use ZipArchive;

if (!defined('GLPI_ROOT')) {
   die("Sorry. You can't access this file directly");
}

class PluginInstaller {

   public function installFromZip(string $zipPath, array $meta): array {
      $pluginsRoot = Utils::pluginsRoot();
      if (!is_dir($pluginsRoot) || !is_writable($pluginsRoot)) {
         return ['ok' => false, 'msg' => 'Diretório de plugins não está gravável: ' . $pluginsRoot];
      }

      $slug = (string)($meta['slug'] ?? '');
      $pluginDir = (string)($meta['plugin_dir'] ?? '');
      if ($pluginDir === '') {
         // assume slug == directory
         $pluginDir = $slug !== '' ? $slug : 'unknown';
      }
      $dest = rtrim($pluginsRoot, '/\\') . DIRECTORY_SEPARATOR . $pluginDir;

      // Extract into a temp dir first (safer), then move into final
      $tmpDir = Utils::tmpFile('wbstore_extract', 'dir');
      // tmpFile created as file-like, we want a directory name:
      @unlink($tmpDir);
      Utils::ensureDir($tmpDir);

      $zip = new ZipArchive();
      if ($zip->open($zipPath) !== true) {
         Utils::rrmdir($tmpDir);
         return ['ok' => false, 'msg' => 'Não consegui abrir o ZIP.'];
      }
      if (!$zip->extractTo($tmpDir)) {
         $zip->close();
         Utils::rrmdir($tmpDir);
         return ['ok' => false, 'msg' => 'Falha ao extrair ZIP.'];
      }
      $zip->close();

      // Detect root folder inside zip
      $root = $this->detectRootFolder($tmpDir);
      if ($root === null) {
         Utils::rrmdir($tmpDir);
         return ['ok' => false, 'msg' => 'ZIP inválido: não achei pasta raiz do plugin.'];
      }

      // Replace old install if exists (safe but direct)
      if (is_dir($dest)) {
         Utils::rrmdir($dest);
      }

      if (!@rename($root, $dest)) {
         // fallback copy
         $ok = $this->copyDir($root, $dest);
         if (!$ok) {
            Utils::rrmdir($tmpDir);
            return ['ok' => false, 'msg' => 'Falha ao mover o plugin para ' . $dest];
         }
      }

      // Cleanup remaining temp
      Utils::rrmdir($tmpDir);

      return ['ok' => true, 'msg' => 'Instalado em: ' . $dest, 'plugin_dir' => $pluginDir];
   }

   private function detectRootFolder(string $tmpDir): ?string {
      // Many plugin zips are like: <pluginname>/setup.php ...
      // We'll pick the first directory under tmpDir that contains setup.php.
      $entries = @scandir($tmpDir);
      if (!$entries) return null;

      foreach ($entries as $e) {
         if ($e === '.' || $e === '..') continue;
         $p = $tmpDir . DIRECTORY_SEPARATOR . $e;
         if (is_dir($p) && is_file($p . DIRECTORY_SEPARATOR . 'setup.php')) {
            return $p;
         }
      }

      // Maybe zip has files directly; then tmpDir itself is root
      if (is_file($tmpDir . DIRECTORY_SEPARATOR . 'setup.php')) {
         return $tmpDir;
      }

      // Search deeper (one level) if needed
      foreach ($entries as $e) {
         if ($e === '.' || $e === '..') continue;
         $p = $tmpDir . DIRECTORY_SEPARATOR . $e;
         if (is_dir($p)) {
            $sub = @scandir($p);
            if (!$sub) continue;
            foreach ($sub as $s) {
               if ($s === '.' || $s === '..') continue;
               $pp = $p . DIRECTORY_SEPARATOR . $s;
               if (is_dir($pp) && is_file($pp . DIRECTORY_SEPARATOR . 'setup.php')) {
                  return $pp;
               }
            }
         }
      }

      return null;
   }

   private function copyDir(string $src, string $dst): bool {
      if (!Utils::ensureDir($dst)) return false;

      $it = new \RecursiveIteratorIterator(
         new \RecursiveDirectoryIterator($src, \FilesystemIterator::SKIP_DOTS),
         \RecursiveIteratorIterator::SELF_FIRST
      );
      foreach ($it as $item) {
         $target = $dst . DIRECTORY_SEPARATOR . $it->getSubPathName();
         if ($item->isDir()) {
            if (!is_dir($target) && !@mkdir($target, 0775, true)) {
               return false;
            }
         } else {
            if (!@copy($item->getPathname(), $target)) {
               return false;
            }
         }
      }
      return true;
   }
}
