<?php

namespace App\Services;

use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Mail;
use ZipArchive;
use App\Models\Setting;

class BackupService
{
    protected $dbHost;
    protected $dbUser;
    protected $dbPass;
    protected $dbName;
    protected $backupPath;

    public function __construct()
    {
        $this->dbHost = env('DB_HOST', '127.0.0.1');
        $this->dbUser = env('DB_USERNAME', 'root');
        $this->dbPass = env('DB_PASSWORD', '');
        $this->dbName = env('DB_DATABASE', 'laravel');
        // Ensure backups folder exists
        $this->backupPath = storage_path('app/backups');
        if (!file_exists($this->backupPath)) {
            mkdir($this->backupPath, 0755, true);
        }
    }

    public function createBackup($type = 'manual')
    {
        $date = now()->format('Y-m-d_H-i-s');
        $filename = "backup_{$this->dbName}_{$date}";
        $sqlPath = "{$this->backupPath}/{$filename}.sql";
        $zipPath = "{$this->backupPath}/{$filename}.zip";

        try {
            // 1. Create SQL Dump
            $this->dumpDatabase($sqlPath);

            // 2. Zip the file
            $this->zipFile($sqlPath, $zipPath);

            // 3. Remove raw SQL file to save space
            if (file_exists($sqlPath)) {
                unlink($sqlPath);
            }

            // 4. Handle Destinations (Email, FTP)
            $this->handleDestinations($zipPath, $filename);

            return [
                'success' => true,
                'path' => $zipPath,
                'filename' => "{$filename}.zip"
            ];

        } catch (Exception $e) {
            Log::error("Backup failed: " . $e->getMessage());
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    protected function dumpDatabase($path)
    {
        // Try to locate mysqldump
        // In XAMPP, it's usually at C:\xampp\mysql\bin\mysqldump.exe
        // We will try a few common paths
        $mysqldump = 'mysqldump'; // Default for global path

        $possiblePaths = [
            'C:\\xampp\\mysql\\bin\\mysqldump.exe',
            'D:\\xampp\\mysql\\bin\\mysqldump.exe',
            '/usr/bin/mysqldump',
            '/usr/local/bin/mysqldump'
        ];

        foreach ($possiblePaths as $files) {
            if (file_exists($files)) {
                $mysqldump = '"' . $files . '"';
                break;
            }
        }

        $command = "{$mysqldump} --user=\"{$this->dbUser}\" --password=\"{$this->dbPass}\" --host=\"{$this->dbHost}\" \"{$this->dbName}\" > \"{$path}\" 2>&1";

        // If password is empty, remove it from command to avoid warning/error
        if (empty($this->dbPass)) {
            $command = "{$mysqldump} --user=\"{$this->dbUser}\" --host=\"{$this->dbHost}\" \"{$this->dbName}\" > \"{$path}\" 2>&1";
        }

        $output = [];
        $returnVar = 0;
        exec($command, $output, $returnVar);

        if ($returnVar !== 0) {
            // Check if file was created and has content despite error code (warnings sometimes trigger non-zero)
            if (!file_exists($path) || filesize($path) == 0) {
                throw new Exception("mysqldump failed with error code $returnVar. Output: " . implode("\n", $output));
            }
        }
    }

    protected function zipFile($source, $destination)
    {
        $zip = new ZipArchive();
        if ($zip->open($destination, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) {
            $zip->addFile($source, basename($source));
            $zip->close();
        } else {
            throw new Exception("Failed to create zip archive");
        }
    }

    protected function handleDestinations($filePath, $filename)
    {
        $settings = Setting::getGroup('backup');

        // Email
        if (($settings['email_enabled'] ?? false) && !empty($settings['email_address'])) {
            try {
                Mail::raw("Attached is the database backup for {$this->dbName}.", function ($message) use ($settings, $filePath, $filename) {
                    $message->to($settings['email_address'])
                        ->subject("Database Backup: {$filename}")
                        ->attach($filePath);
                });
            } catch (Exception $e) {
                Log::error("Backup Email connect failed: " . $e->getMessage());
            }
        }

        // FTP
        if ($settings['ftp_enabled'] ?? false) {
            try {
                // Dynamically configure FTP disk
                $ftpConfig = [
                    'driver' => 'ftp',
                    'host' => $settings['ftp_host'] ?? '',
                    'username' => $settings['ftp_username'] ?? '',
                    'password' => $settings['ftp_password'] ?? '',
                    'port' => 21,
                    // 'root' => $settings['ftp_path'] ?? '/', // Optional
                ];

                // We use a custom disk on the fly? Laravel config doesn't easily support dynamic disks without registering them.
                // Alternative: Use native PHP FTP or reuse an existing disk config if editable.
                // For simplicity, let's assume we update the 'ftp' config in runtime config().

                config(['filesystems.disks.custom_ftp' => $ftpConfig]);

                $remotePath = ($settings['ftp_path'] ?? '/') . "/{$filename}.zip";
                $fileContent = file_get_contents($filePath);

                Storage::disk('custom_ftp')->put($remotePath, $fileContent);

            } catch (Exception $e) {
                Log::error("Backup FTP upload failed: " . $e->getMessage());
            }
        }
    }
}
