<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

use Illuminate\Support\Facades\File;
use JsonException;

/**
 * 执行任务级分批进度（跨 Web 请求 / CLI 续跑，存于 storage 工作区）。
 */
final class HostSystemUpdateExecutionBatchProgressStore
{
    /**
     * @return list<string>
     */
    public function readStableList(string $executionNo, string $listKey): array
    {
        $path = $this->listPathFor($executionNo, $listKey);

        if (! is_file($path)) {
            return [];
        }

        $raw = file_get_contents($path);

        if ($raw === false || trim($raw) === '') {
            return [];
        }

        try {
            /** @var mixed $decoded */
            $decoded = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException) {
            return [];
        }

        if (! is_array($decoded)) {
            return [];
        }

        return array_values(array_filter($decoded, static fn (mixed $item): bool => is_string($item) && $item !== ''));
    }

    /**
     * @param  list<string>  $items
     */
    public function writeStableList(string $executionNo, string $listKey, array $items): void
    {
        HostSystemUpdateWorkspaceStorage::ensureDirectoryExists(
            HostSystemUpdateWorkspaceStorage::executionWorkspaceDirectory($executionNo),
        );

        $encoded = json_encode(array_values($items), JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
        file_put_contents($this->listPathFor($executionNo, $listKey), $encoded);
    }

    public function read(string $executionNo, string $phase): ?HostSystemUpdateBatchProgress
    {
        $path = $this->pathFor($executionNo, $phase);

        if (! is_file($path)) {
            return null;
        }

        $raw = file_get_contents($path);

        if ($raw === false || trim($raw) === '') {
            return null;
        }

        try {
            /** @var array<string, mixed> $decoded */
            $decoded = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException) {
            return null;
        }

        return HostSystemUpdateBatchProgress::fromArray($decoded);
    }

    public function save(string $executionNo, HostSystemUpdateBatchProgress $progress): void
    {
        HostSystemUpdateWorkspaceStorage::ensureDirectoryExists(
            HostSystemUpdateWorkspaceStorage::executionWorkspaceDirectory($executionNo),
        );

        $encoded = json_encode($progress->toArray(), JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
        file_put_contents($this->pathFor($executionNo, $progress->phase), $encoded);
    }

    public function clear(string $executionNo, string $phase): void
    {
        $path = $this->pathFor($executionNo, $phase);

        if (is_file($path)) {
            File::delete($path);
        }
    }

    public function clearList(string $executionNo, string $listKey): void
    {
        $path = $this->listPathFor($executionNo, $listKey);

        if (is_file($path)) {
            File::delete($path);
        }
    }

    /**
     * @return array<string, int>
     */
    public function readStableIndexMap(string $executionNo, string $listKey): array
    {
        $path = $this->listPathFor($executionNo, $listKey);

        if (! is_file($path)) {
            return [];
        }

        $raw = file_get_contents($path);

        if ($raw === false || trim($raw) === '') {
            return [];
        }

        try {
            /** @var mixed $decoded */
            $decoded = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException) {
            return [];
        }

        if (! is_array($decoded)) {
            return [];
        }

        $map = [];

        foreach ($decoded as $pathKey => $index) {
            if (is_string($pathKey) && $pathKey !== '' && is_int($index)) {
                $map[$pathKey] = $index;
            }
        }

        return $map;
    }

    /**
     * @param  array<string, int>  $map
     */
    public function writeStableIndexMap(string $executionNo, string $listKey, array $map): void
    {
        HostSystemUpdateWorkspaceStorage::ensureDirectoryExists(
            HostSystemUpdateWorkspaceStorage::executionWorkspaceDirectory($executionNo),
        );

        $encoded = json_encode($map, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
        file_put_contents($this->listPathFor($executionNo, $listKey), $encoded);
    }

    private function pathFor(string $executionNo, string $phase): string
    {
        return HostSystemUpdateWorkspaceStorage::executionWorkspaceDirectory($executionNo)
            .DIRECTORY_SEPARATOR.'batch-'.preg_replace('/[^a-z0-9_\-]+/i', '-', $phase).'.json';
    }

    private function listPathFor(string $executionNo, string $listKey): string
    {
        return HostSystemUpdateWorkspaceStorage::executionWorkspaceDirectory($executionNo)
            .DIRECTORY_SEPARATOR.'list-'.preg_replace('/[^a-z0-9_\-]+/i', '-', $listKey).'.json';
    }
}
