<?php

namespace App\OldDataMigrations;

use Illuminate\Support\Facades\DB;

abstract class BaseOldDataMigration
{
    protected $old;

    protected $new;

    public static bool $truncateBeforeInsert = false;

    public function __construct()
    {
        $this->old = DB::connection('mysql_old');
        $this->new = DB::connection('mysql');
    }

    abstract public function migrate(): array;

    abstract public function priority(): int;

    protected function oldQuery(string $table)
    {
        return $this->old->table($table);
    }

    protected function truncateIfNeeded(string $table): void
    {
        if (static::$truncateBeforeInsert) {
            $this->new->table($table)->truncate();
        }
    }

    protected function insertBatch(string $table, array $rows, int $chunkSize = 500): int
    {
        if (empty($rows)) {
            return 0;
        }

        $total = 0;

        foreach (array_chunk($rows, $chunkSize) as $chunk) {
            $this->new->table($table)->insert($chunk);
            $total += count($chunk);
        }

        return $total;
    }

    protected function migrateTable(string $table, ?callable $transform = null, ?array $columns = null): int
    {
        $this->truncateIfNeeded($table);

        $rows = $this->oldQuery($table)->get();

        if ($rows->isEmpty()) {
            return 0;
        }

        $rows = $rows->map(function ($row) use ($columns) {
            $data = (array) $row;
            if ($columns !== null) {
                return array_intersect_key($data, array_flip($columns));
            }

            return $data;
        })->toArray();

        if ($transform !== null) {
            $rows = array_map($transform, $rows);
        }

        return $this->insertBatch($table, $rows);
    }

    protected function migrateTableWithoutColumns(string $table, array $skipColumns, ?callable $transform = null): int
    {
        $this->truncateIfNeeded($table);

        $rows = $this->oldQuery($table)->get();

        if ($rows->isEmpty()) {
            return 0;
        }

        $rows = $rows->map(function ($row) use ($skipColumns) {
            $data = (array) $row;

            return array_diff_key($data, array_flip($skipColumns));
        })->toArray();

        if ($transform !== null) {
            $rows = array_map($transform, $rows);
        }

        return $this->insertBatch($table, $rows);
    }
}
