<?php
declare(strict_types=1);

function eaq_install_base_url(): string {
  $scriptName = $_SERVER['SCRIPT_NAME'] ?? '/';
  $dir = dirname($scriptName);       // .../install
  $base = dirname($dir);            // .../<base>
  if ($base === '' || $base === DIRECTORY_SEPARATOR) return '';
  return $base;
}

function eaq_installed_flag_path(): string {
  return __DIR__ . '/../config/installed.flag';
}

function eaq_is_installed(): bool {
  return file_exists(eaq_installed_flag_path());
}

function eaq_storage_root(): string {
  return __DIR__ . '/../storage';
}

function eaq_config_dir(): string {
  return __DIR__ . '/../config';
}

function eaq_config_php_path(): string {
  return eaq_config_dir() . '/config.php';
}

function eaq_env_put(string $key, string $value, string $envPath): void {
  $lines = [];
  if (file_exists($envPath)) {
    $lines = file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
  }
  $found = false;
  foreach ($lines as &$line) {
    if (preg_match('/^\s*' . preg_quote($key, '/') . '\s*=/', $line)) {
      $line = $key . '=' . $value;
      $found = true;
      break;
    }
  }
  unset($line);
  if (!$found) $lines[] = $key . '=' . $value;
  file_put_contents($envPath, implode("\n", $lines) . "\n", LOCK_EX);
}

function eaq_verify_environment(string &$summary): array {
  $results = [];
  $summary = '';

  $phpOk = (PHP_VERSION_ID >= 70400);
  $results[] = ['type' => $phpOk ? 'ok' : 'error', 'label' => 'PHP versão', 'value' => PHP_VERSION];

  $needExt = ['json', 'pdo'];
  $missing = [];
  foreach ($needExt as $ext) {
    if (!extension_loaded($ext)) $missing[] = $ext;
  }
  $pdoDrivers = PDO::getAvailableDrivers();
  $results[] = ['type' => (empty($missing) ? 'ok' : 'error'), 'label' => 'Extensões mínimas', 'value' => empty($missing) ? 'OK' : ('Faltando: ' . implode(', ', $missing))];

  $writableDirs = [eaq_config_dir(), eaq_storage_root()];
  $writable = true;
  foreach ($writableDirs as $dir) {
    if (!is_dir($dir)) {
      $results[] = ['type'=>'error','label'=>'Diretório existe', 'value'=>'Faltando: ' . $dir];
      $writable = false;
      continue;
    }
    $testFile = $dir . '/.write_test_' . uniqid();
    $ok = @file_put_contents($testFile, 'test', LOCK_EX);
    if ($ok === false) {
      $results[] = ['type'=>'error','label'=>'Permissão de escrita', 'value'=>'Sem permissão: ' . $dir];
      $writable = false;
    } else {
      @unlink($testFile);
      $results[] = ['type'=>'ok','label'=>'Permissão de escrita', 'value'=>'OK: ' . $dir];
    }
  }

  // Files essential for this package
  $essential = [
    __DIR__ . '/../app/index.php',
    __DIR__ . '/../app/login.php',
    __DIR__ . '/../app/bootstrap.php',
    __DIR__ . '/../install/index.php',
  ];
  $hasAll = true;
  foreach ($essential as $f) {
    if (!file_exists($f)) {
      $hasAll = false;
      $results[] = ['type'=>'error','label'=>'Arquivo essencial', 'value'=>'Faltando: ' . $f];
    }
  }
  if ($hasAll) $results[] = ['type'=>'ok','label'=>'Arquivos essenciais', 'value'=>'OK'];

  if ($phpOk && empty($missing) && $writable && $hasAll) {
    $summary = 'Ambiente OK.';
  } else {
    $summary = 'Há itens a corrigir antes da instalação.';
  }

  return $results;
}

function eaq_detect_db_mode(array $post): array {
  // Se host vazio => modo mock/local.
  $host = trim((string)($post['db_host'] ?? ''));
  $port = trim((string)($post['db_port'] ?? '3306'));
  $database = trim((string)($post['db_database'] ?? ''));
  $username = trim((string)($post['db_username'] ?? ''));
  $password = (string)($post['db_password'] ?? '');
  if ($host === '' || $database === '') {
    return ['mode' => 'mock'];
  }
  return [
    'mode' => 'mysql',
    'host' => $host,
    'port' => $port !== '' ? $port : '3306',
    'database' => $database,
    'username' => $username,
    'password' => $password,
  ];
}

function eaq_test_db_connection(array $db): array {
  if (($db['mode'] ?? 'mock') !== 'mysql') return ['ok' => true, 'message' => 'Modo mock (sem DB).'];
  $host = $db['host'] ?? '';
  $port = $db['port'] ?? '3306';
  $name = $db['database'] ?? '';
  $user = $db['username'] ?? '';
  $pass = $db['password'] ?? '';

  try {
    $dsn = "mysql:host={$host};port={$port};dbname={$name};charset=utf8mb4";
    $pdo = new PDO($dsn, $user, $pass, [
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
    $stmt = $pdo->query('SELECT 1');
    $stmt->fetch();
    return ['ok' => true, 'message' => 'Conexão OK.'];
  } catch (Throwable $e) {
    return ['ok' => false, 'message' => 'Falha: ' . $e->getMessage()];
  }
}

function eaq_run_sql(array $db, string $sqlFile): array {
  if (($db['mode'] ?? 'mock') !== 'mysql') return ['ok' => true, 'message' => 'Modo mock, sem SQL.'];
  $sqlPath = $sqlFile;
  if (!file_exists($sqlPath)) return ['ok'=>false,'message'=>'SQL file not found: ' . $sqlPath];
  $sql = file_get_contents($sqlPath);
  if ($sql === false) return ['ok'=>false,'message'=>'Could not read SQL file.'];

  try {
    $dsn = "mysql:host={$db['host']};port={$db['port']};dbname={$db['database']};charset=utf8mb4";
    $pdo = new PDO($dsn, $db['username'] ?? '', $db['password'] ?? '', [
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);

    // split statements naive; SQL esperado é simples.
    $statements = array_filter(array_map('trim', preg_split('/;\s*[\r\n]+/', $sql)));
    foreach ($statements as $stmt) {
      if ($stmt !== '') $pdo->exec($stmt . ';');
    }
    return ['ok' => true, 'message' => 'SQL aplicado com sucesso.'];
  } catch (Throwable $e) {
    return ['ok'=>false,'message'=>'Erro SQL: ' . $e->getMessage()];
  }
}

function eaq_write_config(array $cfg): void {
  // Cria config.php e um .env (informativo) na pasta /config.
  $configPhp = __DIR__ . '/../config/config.php';
  $envPath = __DIR__ . '/../config/.env';
  $cfgForPhp = $cfg;

  $envLines = [];
  // db password intentionally stored (demo).
  if (($cfgForPhp['db']['mode'] ?? 'mock') === 'mysql') {
    $db = $cfgForPhp['db'];
    eaq_env_put('DB_HOST', "'" . addslashes((string)($db['host'] ?? '')) . "'", $envPath);
    eaq_env_put('DB_PORT', "'" . addslashes((string)($db['port'] ?? '')) . "'", $envPath);
    eaq_env_put('DB_DATABASE', "'" . addslashes((string)($db['database'] ?? '')) . "'", $envPath);
    eaq_env_put('DB_USERNAME', "'" . addslashes((string)($db['username'] ?? '')) . "'", $envPath);
    eaq_env_put('DB_PASSWORD', "'" . addslashes((string)($db['password'] ?? '')) . "'", $envPath);
  } else {
    eaq_env_put('DB_MODE', "'mock'", $envPath);
  }

  $cfgVarExport = var_export($cfgForPhp, true);
  $php = "<?php\nreturn " . $cfgVarExport . ";\n";
  file_put_contents($configPhp, $php, LOCK_EX);
}

function eaq_seed_admin_and_data(array $cfg, string $adminUsername, string $adminPassword): void {
  $mode = $cfg['db']['mode'] ?? 'mock';
  $hash = password_hash($adminPassword, PASSWORD_DEFAULT);

  if ($mode === 'mysql') {
    $db = $cfg['db'];
    $dsn = "mysql:host={$db['host']};port={$db['port']};dbname={$db['database']};charset=utf8mb4";
    $pdo = new PDO($dsn, $db['username'] ?? '', $db['password'] ?? '', [
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);
    // upsert-like: insert if not exists
    $stmt = $pdo->prepare('SELECT id FROM admin_users WHERE username = ? LIMIT 1');
    $stmt->execute([$adminUsername]);
    $exists = (bool)$stmt->fetch();
    if ($exists) {
      $upd = $pdo->prepare('UPDATE admin_users SET password_hash = ?, updated_at = NOW() WHERE username = ?');
      $upd->execute([$hash, $adminUsername]);
    } else {
      $ins = $pdo->prepare('INSERT INTO admin_users (username, password_hash, role, created_at) VALUES (?, ?, ?, NOW())');
      $ins->execute([$adminUsername, $hash, 'admin']);
    }
  } else {
    $adminMock = eaq_read_json('admin_mock.json', []);
    $adminMock[$adminUsername] = [
      'username' => $adminUsername,
      'password_hash' => $hash,
      'role' => 'admin',
      'created_at' => gmdate('c'),
    ];
    eaq_write_json('admin_mock.json', $adminMock);
  }

  // seed CRM data snapshot if missing
  $existing = eaq_read_json('mock_crm.json', null);
  if ($existing === null) {
    require_once __DIR__ . '/../app/mock_data.php';
    $data = eaq_seed_mock_crm();
    eaq_write_json('mock_crm.json', $data);
  }
}

function eaq_finish_installation(): void {
  $flag = eaq_installed_flag_path();
  if (!is_dir(dirname($flag))) mkdir(dirname($flag), 0775, true);
  file_put_contents($flag, (string)time(), LOCK_EX);

  // Desabilita /install sem depender de permissões/htaccess.
  // O /install continuará a existir, mas o wizard mostra "instalação concluída".
  $disabled = __DIR__ . '/.disabled.flag';
  file_put_contents($disabled, (string)time(), LOCK_EX);
}

