<?php
if (!defined('ABSPATH')) exit;

class WizMig_DBDump {
  private $wpdb; private $from; private $to;
  public function __construct($wpdb, $fromDomain, $toDomain) {
    $this->wpdb = $wpdb; $this->from = rtrim($fromDomain,'/'); $this->to = rtrim($toDomain,'/');
  }
  public function export_gz() {
    $upload_dir = wp_upload_dir();
    $work = trailingslashit($upload_dir['basedir']) . 'wizhosting-migrator';
    if (!wp_mkdir_p($work)) throw new Exception('Cannot create work dir: '.$work);
    $path = trailingslashit($work) . 'wiz_db.sql.gz';
    $gz = gzopen($path, 'wb9'); if (!$gz) throw new Exception('Cannot open gz');
    $tables = $this->wpdb->get_col('SHOW TABLES');
    foreach ($tables as $table) $this->dump_table($gz, $table);
    gzclose($gz); return $path;
  }
  private function dump_table($gz, $table) {
    $row = $this->wpdb->get_row("SHOW CREATE TABLE `$table`", ARRAY_N);
    $create = $row[1] ?? '';
    gzwrite($gz, "DROP TABLE IF EXISTS `$table`;\n$create;\n\n");
    $count = (int)$this->wpdb->get_var("SELECT COUNT(*) FROM `$table`");
    $offset=0; $limit=500;
    $cols = $this->wpdb->get_col("SHOW COLUMNS FROM `$table`", 0);
    $colList = implode('`,`', array_map(function($c){ return str_replace('`','``',$c); }, $cols));
    while ($offset < $count) {
      $rows = $this->wpdb->get_results("SELECT * FROM `$table` LIMIT $offset,$limit", ARRAY_A);
      if (!$rows) break;
      $values=[];
      foreach ($rows as $r) {
        $vals=[];
        foreach ($cols as $c) {
          $v = array_key_exists($c,$r) ? $r[$c] : null;
          if ($this->from !== $this->to && is_string($v)) $v = $this->replace_serialization_safe($v, $this->from, $this->to);
          if ($v === null) $vals[]='NULL'; else $vals[]="'".esc_sql($v)."'";
        }
        $values[]='('.implode(',',$vals).')';
      }
      if ($values) gzwrite($gz, "INSERT INTO `$table` (`$colList`) VALUES\n".implode(",\n",$values).";\n");
      $offset += $limit;
    }
    gzwrite($gz, "\n");
  }
  private function replace_serialization_safe($data,$search,$replace) {
    if (!is_string($data)) return $data;
    $maybe=@unserialize($data);
    if ($maybe !== false || $data==='b:0;') { $fixed=$this->walk_replace($maybe,$search,$replace); return serialize($fixed); }
    return str_replace($search,$replace,$data);
  }
  private function walk_replace($value,$search,$replace) {
    if (is_array($value)) { foreach ($value as $k=>$v) $value[$k]=$this->walk_replace($v,$search,$replace); return $value; }
    if (is_object($value)) { foreach ($value as $k=>$v) $value->$k=$this->walk_replace($v,$search,$replace); return $value; }
    if (is_string($value)) return str_replace($search,$replace,$value);
    return $value;
  }
}
