<?php

namespace App\Services\Update;

use App\Contracts\ProductOwnerClientContract;
use App\DTOs\ProductOwner\AdminUpdateCheckData;
use App\Services\Integrity\IntegrityManifestSyncService;
use App\Services\Settings\SettingService;
use App\Support\PlatformVersion;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;

class AdminUpdateService
{
    public function __construct(
        private readonly ProductOwnerClientContract $productOwnerClient,
        private readonly SettingService $settings,
        private readonly IntegrityManifestSyncService $integrityManifestSync,
    ) {}

    /**
     * @return array{version: string, build: string, channel: string}
     */
    public function currentVersion(): array
    {
        return PlatformVersion::current();
    }

    public function checkForUpdate(bool $force = false): AdminUpdateCheckData
    {
        $current = $this->currentVersion();
        $cacheKey = 'admin.update.check';

        if (! $force) {
            $cached = Cache::get($cacheKey);
            if ($cached instanceof AdminUpdateCheckData) {
                return $cached;
            }
        }

        $installationId = (string) config('product_owner.installation_id', '');
        $result = $installationId !== ''
            ? $this->productOwnerClient->checkAdminUpdate($installationId, $current['version'])
            : AdminUpdateCheckData::unavailable($current);

        $this->settings->updateMany([
            'update.last_checked_at' => [
                'value' => now()->toIso8601String(),
                'category' => 'update',
                'type' => 'string',
            ],
        ]);

        Cache::put($cacheKey, $result, config('update.check_cache_ttl', 3600));

        if ($installationId !== '' && ! $result->platformUnavailable) {
            $this->integrityManifestSync->syncForCurrentVersion();
        }

        return $result;
    }

    public function lastCheckedAt(): ?Carbon
    {
        $value = $this->settings->get('update.last_checked_at');

        if (! is_string($value) || trim($value) === '') {
            return null;
        }

        try {
            return Carbon::parse($value);
        } catch (\Throwable) {
            return null;
        }
    }

    public function tempPath(): string
    {
        $configured = trim((string) $this->settings->get('update.temp_path', ''));

        if ($configured !== '') {
            return $configured;
        }

        return (string) config('update.default_temp_path');
    }

    public function tempPathConfigured(): bool
    {
        $path = $this->tempPath();

        return $path !== '' && File::isDirectory($path) && File::isWritable($path);
    }

    public function ensureTempPath(): void
    {
        $path = $this->tempPath();

        if ($path === '') {
            return;
        }

        if (! File::isDirectory($path)) {
            File::makeDirectory($path, 0755, true);
        }
    }

    public function canApplyUpdate(AdminUpdateCheckData $check): bool
    {
        return $check->updateAvailable
            && $this->tempPathConfigured()
            && ! empty($check->downloadUrl);
    }

    public function saveTempPath(string $path): void
    {
        $this->settings->updateMany([
            'update.temp_path' => [
                'value' => $path,
                'category' => 'update',
                'type' => 'string',
            ],
        ]);
    }
}
