<?php

namespace App\Services;

use App\Models\App;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use ZipArchive;

class ZipArchiveService
{
    private string $disk = 'public';

    private string $directory = 'exports';

    public function __construct()
    {
        Storage::disk($this->disk)->makeDirectory($this->directory);
    }

    /**
     * List available ZIP archives with metadata and download URLs.
     */
    public function listArchives(): array
    {
        $files = Storage::disk($this->disk)->files($this->directory);
        $archives = [];

        foreach ($files as $file) {
            if (strtolower(pathinfo($file, PATHINFO_EXTENSION)) !== 'zip') {
                continue;
            }

            $archives[] = [
                'name' => basename($file),
                'size' => Storage::disk($this->disk)->size($file),
                'created' => Storage::disk($this->disk)->lastModified($file),
                'download_url' => Storage::disk($this->disk)->url($file),
            ];
        }

        usort($archives, fn (array $a, array $b) => $b['created'] <=> $a['created']);

        return $archives;
    }

    /**
     * Build a ZIP archive for the provided app collection.
     */
    public function createFromAppCollection(string $collectionName, array $selectedApps): string
    {
        $safeName = Str::slug($collectionName) ?: 'collection';
        $fileName = sprintf('%s-%s.zip', $safeName, now()->format('YmdHis'));
        $relativePath = $this->directory . '/' . $fileName;
        $absolutePath = Storage::disk($this->disk)->path($relativePath);

        $zip = new ZipArchive();
        if ($zip->open($absolutePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            throw new \RuntimeException('Unable to create ZIP archive.');
        }

        $apps = App::whereIn('id', $selectedApps)->get(['id', 'name', 'package_name']);
        if ($apps->isEmpty()) {
            $zip->close();
            Storage::disk($this->disk)->delete($relativePath);

            throw new \RuntimeException('No apps found for the provided selection.');
        }

        $zip->addFromString(
            'README.txt',
            "Exported apps for collection: {$collectionName}\nGenerated at: " . now()->toDateTimeString() . "\n"
        );

        foreach ($apps as $app) {
            $zip->addFromString(
                "app-{$app->id}.txt",
                "Name: {$app->name}\nPackage: {$app->package_name}\n"
            );
        }

        $zip->close();

        return $absolutePath;
    }

    /**
     * Resolve an archive path if it exists.
     */
    public function getArchivePath(string $fileName): ?string
    {
        $relativePath = $this->directory . '/' . basename($fileName);

        if (!Storage::disk($this->disk)->exists($relativePath)) {
            return null;
        }

        return Storage::disk($this->disk)->path($relativePath);
    }

    /**
     * Delete ZIP archives older than the given number of days.
     */
    public function cleanupOldArchives(int $days): int
    {
        $threshold = now()->subDays($days)->getTimestamp();
        $deleted = 0;

        foreach (Storage::disk($this->disk)->files($this->directory) as $file) {
            if (strtolower(pathinfo($file, PATHINFO_EXTENSION)) !== 'zip') {
                continue;
            }

            if (Storage::disk($this->disk)->lastModified($file) < $threshold) {
                Storage::disk($this->disk)->delete($file);
                $deleted++;
            }
        }

        return $deleted;
    }
}