<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Symfony\Component\Process\Process;

class DatabaseBackup extends Command
{
    protected $signature = 'db:backup {--keep=14 : Jumlah file backup terbaru yang dipertahankan}';
    protected $description = 'Backup database MySQL OKE Laundry ke storage/app/backups/ menggunakan mysqldump';

    public function handle(): int
    {
        $connection = config('database.default');
        $cfg = config('database.connections.' . $connection);

        if (($cfg['driver'] ?? null) !== 'mysql') {
            $this->error('Backup ini khusus driver MySQL. Driver aktif: ' . ($cfg['driver'] ?? 'unknown'));
            return self::FAILURE;
        }

        $dir = storage_path('app/backups');
        File::ensureDirectoryExists($dir);

        $filename = sprintf('%s_%s.sql', $cfg['database'], now()->format('Ymd_His'));
        $target = $dir . DIRECTORY_SEPARATOR . $filename;

        $mysqldump = $this->resolveMysqldump();
        $this->info('Menggunakan mysqldump: ' . $mysqldump);

        $command = [
            $mysqldump,
            '-h', (string) ($cfg['host'] ?? '127.0.0.1'),
            '-P', (string) ($cfg['port'] ?? '3306'),
            '-u', (string) ($cfg['username'] ?? 'root'),
        ];

        if (!empty($cfg['password'])) {
            // Password lewat env agar tidak muncul di command line
            $command[] = '--defaults-extra-file=' . $this->writeMyCnf($cfg);
        }

        $command = array_merge($command, [
            '--single-transaction',
            '--quick',
            '--routines',
            '--default-character-set=utf8mb4',
            $cfg['database'],
        ]);

        $process = new Process($command, null, null, null, 600);
        $process->run(function ($type, $buffer) use ($target) {
            if ($type === Process::OUT) {
                File::append($target, $buffer);
            }
        });

        if (!$process->isSuccessful()) {
            $this->error('Backup gagal: ' . trim($process->getErrorOutput()));
            if (File::exists($target)) {
                File::delete($target);
            }
            return self::FAILURE;
        }

        $size = number_format(File::size($target) / 1024, 1) . ' KB';
        $this->info("Backup sukses: {$target} ({$size})");

        $this->rotate($dir, (int) $this->option('keep'));

        return self::SUCCESS;
    }

    private function resolveMysqldump(): string
    {
        // Prefer Laragon's mysqldump (versi cocok dengan Laragon MySQL),
        // baru fallback ke PATH atau XAMPP.
        $glob = glob('C:\\laragon\\bin\\mysql\\*\\bin\\mysqldump.exe');
        if (!empty($glob)) {
            return $glob[0];
        }

        $candidates = [
            'mysqldump',
            'C:\\xampp\\mysql\\bin\\mysqldump.exe',
        ];
        foreach ($candidates as $c) {
            $check = new Process([$c, '--version']);
            $check->run();
            if ($check->isSuccessful()) {
                return $c;
            }
        }

        return 'mysqldump';
    }

    private function writeMyCnf(array $cfg): string
    {
        $tmp = tempnam(sys_get_temp_dir(), 'okl_my_');
        $contents = "[client]\nuser=" . ($cfg['username'] ?? 'root') . "\npassword=\"" . ($cfg['password'] ?? '') . "\"\nhost=" . ($cfg['host'] ?? '127.0.0.1') . "\nport=" . ($cfg['port'] ?? '3306') . "\n";
        file_put_contents($tmp, $contents);
        register_shutdown_function(static function () use ($tmp) {
            if (is_file($tmp)) {
                @unlink($tmp);
            }
        });
        return $tmp;
    }

    private function rotate(string $dir, int $keep): void
    {
        if ($keep <= 0) {
            return;
        }
        $files = collect(File::files($dir))
            ->filter(fn ($f) => str_ends_with($f->getFilename(), '.sql'))
            ->sortByDesc(fn ($f) => $f->getMTime())
            ->values();

        if ($files->count() <= $keep) {
            return;
        }

        $files->slice($keep)->each(function ($f) {
            File::delete($f->getPathname());
            $this->line('Hapus backup lama: ' . $f->getFilename());
        });
    }
}
