<?php

declare(strict_types=1);

namespace App\Business\MasterData;

use App\Business\MasterData\Enums\RegionLevel;
use App\Models\DberpRegion;

class DberpRegionAddressService
{
    public function __construct(
        private readonly DberpRegionGovernanceService $regionGovernanceService,
    ) {}

    /**
     * @return array<string, string>
     */
    public function countryOptions(): array
    {
        return (array) config('dberp.regions.country_labels', []);
    }

    public function defaultCountryCode(): ?string
    {
        $defaultCountryCode = config('dberp.regions.default_country_code');

        if (is_string($defaultCountryCode) && $defaultCountryCode !== '') {
            return $defaultCountryCode;
        }

        $countryOptions = $this->countryOptions();

        return $countryOptions === [] ? null : array_key_first($countryOptions);
    }

    public function shouldOfferCountryChoice(): bool
    {
        return count($this->countryOptions()) > 1;
    }

    /**
     * @return array<int, string>
     */
    public function provinceOptions(?string $countryCode, ?int $currentRegionId = null): array
    {
        return $this->regionGovernanceService->provinceOptions($countryCode, $currentRegionId);
    }

    /**
     * @return array<int, string>
     */
    public function cityOptions(int|string|null $provinceRegionId, ?int $currentRegionId = null): array
    {
        return $this->regionGovernanceService->cityOptions($provinceRegionId, $currentRegionId);
    }

    /**
     * @return array<int, string>
     */
    public function districtOptions(int|string|null $cityRegionId, ?int $currentRegionId = null): array
    {
        return $this->regionGovernanceService->districtOptions($cityRegionId, $currentRegionId);
    }

    /**
     * @param  array<string, mixed>  $data
     * @return array<string, mixed>
     */
    public function fillFormData(array $data, ?DberpRegion $region): array
    {
        $data['country_code'] = $data['country_code'] ?? $region?->country_code ?? $this->defaultCountryCode();
        $data['province_region_id'] = null;
        $data['city_region_id'] = null;
        $data['district_region_id'] = null;

        if (! $region instanceof DberpRegion) {
            return $data;
        }

        $chain = [];
        $current = $region;

        while ($current instanceof DberpRegion) {
            $chain[] = $current;
            $current = $current->parent_id === null
                ? null
                : DberpRegion::query()->find($current->parent_id);
        }

        foreach ($chain as $node) {
            match ((string) $node->level) {
                RegionLevel::Province->value => $data['province_region_id'] = $node->getKey(),
                RegionLevel::City->value => $data['city_region_id'] = $node->getKey(),
                RegionLevel::District->value => $data['district_region_id'] = $node->getKey(),
                default => null,
            };
        }

        if ($data['district_region_id'] !== null && $data['city_region_id'] === null) {
            $district = DberpRegion::query()->find($data['district_region_id']);
            $data['city_region_id'] = $district?->parent_id;
        }

        if ($data['city_region_id'] !== null && $data['province_region_id'] === null) {
            $city = DberpRegion::query()->find($data['city_region_id']);
            $data['province_region_id'] = $city?->parent_id;
        }

        return $data;
    }

    /**
     * @param  array<string, mixed>  $data
     * @return array<string, mixed>
     */
    public function prepareFormDataForSave(array $data, ?DberpRegion $currentRegion = null): array
    {
        $districtRegionId = isset($data['district_region_id']) && $data['district_region_id'] !== null && $data['district_region_id'] !== ''
            ? (int) $data['district_region_id']
            : null;

        unset($data['province_region_id'], $data['city_region_id'], $data['district_region_id'], $data['region_id']);

        $countryCode = filled($data['country_code'] ?? null) ? (string) $data['country_code'] : null;

        // 单国部署用 Hidden 承载 country_code；若 Livewire 状态未带上，仍按默认国家写入，避免误清空
        if ($countryCode === null && ! $this->shouldOfferCountryChoice() && filled($this->defaultCountryCode())) {
            $countryCode = (string) $this->defaultCountryCode();
        }

        if ($countryCode === null) {
            $data['country_code'] = null;
            $data['region_id'] = null;
            $data['region_name_snapshot'] = null;

            return $data;
        }

        if ($districtRegionId === null) {
            $data['country_code'] = $countryCode;
            $data['region_id'] = null;
            $data['region_name_snapshot'] = null;

            return $data;
        }

        $region = $this->regionGovernanceService->resolveMasterDataDistrictRegion($districtRegionId, $currentRegion);

        $data['country_code'] = $region->country_code;
        $data['region_id'] = $region->getKey();
        $data['region_name_snapshot'] = $region->merger_name;

        return $data;
    }

    public function formatCountryLabel(?string $countryCode): string
    {
        if (blank($countryCode)) {
            return __('dberp.messages.region_not_set');
        }

        return $this->countryOptions()[$countryCode] ?? (string) $countryCode;
    }

    public function formatRegionLabel(?string $regionSnapshot, ?DberpRegion $region): string
    {
        if (filled($regionSnapshot)) {
            return $this->formatRegionPath((string) $regionSnapshot);
        }

        if ($region instanceof DberpRegion && filled($region->merger_name)) {
            return $this->formatRegionPath((string) $region->merger_name);
        }

        return __('dberp.messages.region_not_set');
    }

    public function formatRegionAddressSummary(
        ?string $countryCode,
        ?string $regionSnapshot,
        ?string $address,
        ?DberpRegion $region = null,
        ?string $fallbackCountryCode = null,
        ?string $fallbackRegionSnapshot = null,
        ?string $fallbackAddress = null,
    ): string {
        $resolvedRegion = filled($regionSnapshot)
            ? $this->formatRegionPath((string) $regionSnapshot)
            : (filled($fallbackRegionSnapshot)
                ? $this->formatRegionPath((string) $fallbackRegionSnapshot)
                : ($region instanceof DberpRegion && filled($region->merger_name)
                    ? $this->formatRegionPath((string) $region->merger_name)
                    : null));
        $resolvedCountry = filled($countryCode) ? $countryCode : $fallbackCountryCode;
        $resolvedAddress = filled($address) ? $address : $fallbackAddress;

        $parts = [];

        if (filled($resolvedRegion)) {
            $parts[] = (string) $resolvedRegion;
        } elseif (filled($resolvedCountry)) {
            $parts[] = $this->formatCountryLabel($resolvedCountry);
        }

        if (filled($resolvedAddress)) {
            $parts[] = (string) $resolvedAddress;
        }

        return $parts === []
            ? __('dberp.messages.address_detail_not_set')
            : implode(' ', $parts);
    }

    public function formatAddressDetail(?string $address): string
    {
        return filled($address) ? (string) $address : __('dberp.messages.address_detail_not_set');
    }

    public function formatRegionPath(?string $path): string
    {
        if (blank($path)) {
            return __('dberp.messages.region_not_set');
        }

        return str_replace('/', ' / ', (string) $path);
    }
}
