<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Services\SupportCenter;

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

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

        if (! is_file($path)) {
            if ($required) {
                throw new RuntimeException("系统更新稳定清单不存在：{$listKey}");
            }

            return [];
        }

        $raw = file_get_contents($path);

        if ($raw === false || trim($raw) === '') {
            throw new RuntimeException("系统更新稳定清单无法读取：{$listKey}");
        }

        try {
            /** @var mixed $decoded */
            $decoded = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $exception) {
            throw new RuntimeException("系统更新稳定清单已损坏：{$listKey}", previous: $exception);
        }

        if (! is_array($decoded)) {
            throw new RuntimeException("系统更新稳定清单格式无效：{$listKey}");
        }

        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::replace($this->listPathFor($executionNo, $listKey), $encoded.PHP_EOL);
    }

    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) === '') {
            throw new RuntimeException("系统更新批次进度无法读取：{$phase}");
        }

        try {
            /** @var array<string, mixed> $decoded */
            $decoded = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $exception) {
            throw new RuntimeException("系统更新批次进度已损坏：{$phase}", previous: $exception);
        }

        if (! is_array($decoded)) {
            throw new RuntimeException("系统更新批次进度格式无效：{$phase}");
        }

        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::replace($this->pathFor($executionNo, $progress->phase), $encoded.PHP_EOL);
    }

    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, bool $required = false): array
    {
        $path = $this->listPathFor($executionNo, $listKey);

        if (! is_file($path)) {
            if ($required) {
                throw new RuntimeException("系统更新稳定索引不存在：{$listKey}");
            }

            return [];
        }

        $raw = file_get_contents($path);

        if ($raw === false || trim($raw) === '') {
            throw new RuntimeException("系统更新稳定索引无法读取：{$listKey}");
        }

        try {
            /** @var mixed $decoded */
            $decoded = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $exception) {
            throw new RuntimeException("系统更新稳定索引已损坏：{$listKey}", previous: $exception);
        }

        if (! is_array($decoded)) {
            throw new RuntimeException("系统更新稳定索引格式无效：{$listKey}");
        }

        $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::replace($this->listPathFor($executionNo, $listKey), $encoded.PHP_EOL);
    }

    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';
    }
}
