<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use ZipArchive;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;

class BuildDeployZip extends Command
{
    protected $signature = 'app:build-zip
        {--o= : Duong dan output file zip (mac dinh: kocbooking-deploy.zip)}';

    protected $description = 'Nen cac thu muc va file can thiet de day len web hosting';

    protected array $includePaths = [
        'app',
        'bootstrap',
        'config',
        'public',
        'resources',
        'routes',
        'storage',
        //  'vendor',
    ];

    protected array $includeFiles = [
        // '.env',
        'artisan',
        'composer.json',
        'composer.lock',
        'package.json',
        'pnpm-lock.yaml',
        'tailwind.config.js',
        'postcss.config.js',
    ];

    protected array $excludeInside = [
        'node_modules',
        '.git',
        '.idea',
        '.vscode',
        '__pycache__',
        '.DS_Store',
        'Thumbs.db',
        'public/uploads/briefs',
    ];

    public function handle(): int
    {
        $outputPath = $this->option('o') ?: getcwd() . DIRECTORY_SEPARATOR . 'kocbooking-deploy.zip';

        if (!extension_loaded('zip')) {
            $this->error('Thieu PHP extension "zip". Cai dat de su dung lenh nay.');
            return self::FAILURE;
        }

        $basePath = base_path();
        $zip = new ZipArchive();

        if ($zip->open($outputPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            $this->error('Khong the tao file zip tai: ' . $outputPath);
            return self::FAILURE;
        }

        foreach ($this->includePaths as $path) {
            $fullPath = $basePath . DIRECTORY_SEPARATOR . $path;
            if (!is_dir($fullPath)) {
                $this->warn("Khong tim thay thu muc: {$path}, bo qua.");
                continue;
            }
            $this->addDirToZip($zip, $fullPath, $path);
        }

        foreach ($this->includeFiles as $file) {
            $fullPath = $basePath . DIRECTORY_SEPARATOR . $file;
            if (!is_file($fullPath)) {
                $this->warn("Khong tim thay file: {$file}, bo qua.");
                continue;
            }
            $zip->addFile($fullPath, $file);
        }

        $zip->close();

        $size = filesize($outputPath);
        $sizeStr = $this->formatSize($size);
        $this->info("Da tao file zip thanh cong: {$outputPath} ({$sizeStr})");

        return self::SUCCESS;
    }

    protected function addDirToZip(ZipArchive $zip, string $realPath, string $relativePath): void
    {
        $files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($realPath, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::LEAVES_ONLY
        );

        foreach ($files as $file) {
            $fileRealPath = $file->getRealPath();
            $localPath = $relativePath . '/' . $files->getSubIterator()->getSubPathname();
            $localPath = str_replace('\\', '/', $localPath);

            if ($this->shouldExclude($fileRealPath, $localPath)) {
                continue;
            }

            $zip->addFile($fileRealPath, $localPath);
        }
    }

    protected function shouldExclude(string $realPath, string $localPath): bool
    {
        foreach ($this->excludeInside as $pattern) {
            if (str_contains($realPath, DIRECTORY_SEPARATOR . $pattern . DIRECTORY_SEPARATOR)) {
                return true;
            }
            if (str_ends_with($realPath, DIRECTORY_SEPARATOR . $pattern)) {
                return true;
            }
            if (str_contains($localPath, $pattern . '/')) {
                return true;
            }
            if (str_ends_with($localPath, $pattern)) {
                return true;
            }
        }
        return false;
    }

    protected function formatSize(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB'];
        $i = 0;
        while ($bytes >= 1024 && $i < count($units) - 1) {
            $bytes /= 1024;
            $i++;
        }
        return round($bytes, 2) . ' ' . $units[$i];
    }
}
