<?php

namespace Core\App\Services;

use Core\App\Integrations\Shipping\MaystroClient;
use Core\App\Models\ShippingIntegrationModel;

class MaystroLocationService
{
    protected string $cacheDir;
    protected string $officialWilayasPath;

    public function __construct()
    {
        $this->cacheDir = ROOT_PATH . '/storage/cache/maystro';
        $this->officialWilayasPath = ROOT_PATH . '/storage/data/maystro_wilayas.json';
        if (!is_dir($this->cacheDir)) {
            @mkdir($this->cacheDir, 0775, true);
        }
    }

    protected function integration(): ?array
    {
        $integration = (new ShippingIntegrationModel())->getByProvider('maystro');
        if (!$integration || (int)($integration['is_active'] ?? 0) !== 1 || trim((string)($integration['api_token'] ?? '')) === '') {
            return null;
        }
        return $integration;
    }

    protected function client(): ?MaystroClient
    {
        $integration = $this->integration();
        return $integration ? MaystroClient::fromIntegration($integration) : null;
    }

    protected function cachePath(string $name): string
    {
        return $this->cacheDir . '/' . ltrim($name, '/');
    }

    protected function readCache(string $name): array
    {
        $path = $this->cachePath($name);
        if (!is_file($path)) {
            return [];
        }
        $raw = @file_get_contents($path);
        $decoded = json_decode((string)$raw, true);
        return is_array($decoded) ? $decoded : [];
    }

    protected function writeCache(string $name, array $data): void
    {
        if (empty($data)) {
            return;
        }
        @file_put_contents($this->cachePath($name), json_encode(array_values($data), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
    }

    /** @return array{success:bool,data:array,message:?string,source:string} */
    public function getWilayas(): array
    {
        $documented = $this->documentedWilayas();
        $official = $this->loadOfficialWilayasFile();
        $baseline = $this->mergeWilayaSets($documented, $official);

        $client = $this->client();
        $message = null;
        if ($client) {
            $languages = ['fr', 'en', 'ar'];
            $apiSets = [];
            foreach ($languages as $lang) {
                $res = $client->getWilayas($lang);
                if (!empty($res['success']) && is_array($res['data'] ?? null)) {
                    $normalized = $this->normalizeWilayas((array)$res['data'], $lang);
                    if (!empty($normalized)) {
                        $apiSets[] = $normalized;
                    }
                }
                $message = is_string($res['message'] ?? null) ? $res['message'] : (is_string($res['error'] ?? null) ? $res['error'] : $message);
            }
            if (!empty($apiSets)) {
                $apiMerged = $this->mergeWilayaSets(...$apiSets);
                if (count($apiMerged) >= count($baseline)) {
                    $this->writeCache('wilayas.json', $apiMerged);
                    return ['success' => true, 'data' => $apiMerged, 'message' => $message, 'source' => 'api'];
                }
                $merged = $this->mergeWilayaSets($apiMerged, $baseline);
                $this->writeCache('wilayas.json', $merged);
                return ['success' => true, 'data' => $merged, 'message' => $message ?: 'api_plus_documented', 'source' => 'api_plus_documented'];
            }
        } else {
            $message = 'maystro_not_active';
        }

        if (!empty($baseline)) {
            $this->writeCache('wilayas.json', $baseline);
            return ['success' => true, 'data' => $baseline, 'message' => 'documented_wilayas', 'source' => 'documented_wilayas'];
        }

        $cached = $this->readCache('wilayas.json');
        if (!empty($cached)) {
            return ['success' => true, 'data' => $cached, 'message' => 'cache', 'source' => 'cache'];
        }

        return ['success' => false, 'data' => [], 'message' => $message ?? null, 'source' => 'none'];
    }

    /** @return array{success:bool,data:array,message:?string,source:string} */
    public function getCommunes(int $wilayaId): array
    {
        $wilayaId = (int)$wilayaId;
        if ($wilayaId <= 0) {
            return ['success' => false, 'data' => [], 'message' => 'invalid_wilaya', 'source' => 'none'];
        }

        $client = $this->client();
        if (!$client) {
            return ['success' => false, 'data' => [], 'message' => 'maystro_not_active', 'source' => 'none'];
        }

        $res = $client->getCommunes($wilayaId);
        $data = $this->normalizeCommunes((array)($res['data'] ?? []));
        if (!empty($res['success']) && !empty($data)) {
            $this->writeCache('communes_' . $wilayaId . '.json', $data);
            return ['success' => true, 'data' => $data, 'message' => $res['message'] ?? null, 'source' => 'api'];
        }

        $cached = $this->readCache('communes_' . $wilayaId . '.json');
        if (!empty($cached)) {
            return ['success' => true, 'data' => $this->normalizeCommunes($cached), 'message' => 'cache', 'source' => 'cache'];
        }

        return ['success' => false, 'data' => [], 'message' => $res['message'] ?? ($res['error'] ?? null), 'source' => 'none'];
    }

    public function findWilayaBySavedState(?string $stateCode, ?string $stateName): ?array
    {
        $wilayas = $this->getWilayas()['data'] ?? [];
        $stateCode = trim((string)$stateCode);
        $stateName = trim((string)$stateName);

        if ($stateCode !== '') {
            foreach ($wilayas as $wilaya) {
                if ((string)($wilaya['code'] ?? '') === $stateCode) {
                    return $wilaya;
                }
            }
            $stateId = (int)ltrim($stateCode, '0');
            if ($stateId > 0) {
                foreach ($wilayas as $wilaya) {
                    if ((int)($wilaya['id'] ?? 0) === $stateId) {
                        return $wilaya;
                    }
                }
            }
        }

        if ($stateName !== '') {
            $needle = $this->normalizeText($stateName);
            foreach ($wilayas as $wilaya) {
                $haystacks = [
                    $this->normalizeText((string)($wilaya['name'] ?? '')),
                    $this->normalizeText((string)($wilaya['ar_name'] ?? '')),
                ];
                if (in_array($needle, $haystacks, true)) {
                    return $wilaya;
                }
            }
        }

        return null;
    }




    protected function documentedWilayasList(): array
    {
        return [
            [1, 'Adrar'],
            [2, 'Chlef'],
            [3, 'Laghouat'],
            [4, 'Oum El Bouaghi'],
            [5, 'Batna'],
            [6, 'Bejaia'],
            [7, 'Biskra'],
            [8, 'Bechar'],
            [9, 'Blida'],
            [10, 'Bouira'],
            [12, 'Tebessa'],
            [13, 'Tlemcen'],
            [14, 'Tiaret'],
            [15, 'Tizi Ouzou'],
            [16, 'Alger'],
            [17, 'Djelfa'],
            [18, 'Jijel'],
            [19, 'Setif'],
            [20, 'Saida'],
            [21, 'Skikda'],
            [22, 'Sidi Bel Abbes'],
            [23, 'Annaba'],
            [24, 'Guelma'],
            [25, 'Constantine'],
            [26, 'Medea'],
            [27, 'Mostaganem'],
            [28, "M'Sila"],
            [29, 'Mascara'],
            [30, 'Ouargla'],
            [31, 'Oran'],
            [32, 'El Bayadh'],
            [34, 'Bordj Bou Arreridj'],
            [35, 'Boumerdes'],
            [36, 'El Tarf'],
            [38, 'Tissemsilt'],
            [39, 'El Oued'],
            [40, 'Khenchela'],
            [41, 'Souk Ahras'],
            [42, 'Tipaza'],
            [43, 'Mila'],
            [44, 'Ain Defla'],
            [45, 'Naama'],
            [46, 'Ain Temouchent'],
            [47, 'Ghardaia'],
            [48, 'Relizane'],
            [49, 'Timimoun'],
            [51, 'Ouled Djellal'],
            [55, 'Touggourt'],
            [57, 'El M’ghaier'],
            [58, 'El Meniaa'],
        ];
    }

    protected function documentedWilayas(): array
    {
        return $this->normalizeWilayas($this->documentedWilayasList(), 'fr');
    }

    protected function mergeWilayaSets(array ...$sets): array
    {
        $merged = [];
        foreach ($sets as $set) {
            foreach ($this->normalizeWilayas($set, 'fr') as $row) {
                $id = (int)($row['id'] ?? 0);
                if ($id <= 0) {
                    continue;
                }
                $current = $merged[$id] ?? ['id' => $id, 'code' => str_pad((string)$id, 2, '0', STR_PAD_LEFT), 'name' => '', 'ar_name' => ''];
                if (($current['name'] ?? '') === '' && !empty($row['name'])) {
                    $current['name'] = $row['name'];
                }
                if (($current['ar_name'] ?? '') === '' && !empty($row['ar_name'])) {
                    $current['ar_name'] = $row['ar_name'];
                }
                if (!empty($row['code'])) {
                    $current['code'] = str_pad((string)$row['code'], 2, '0', STR_PAD_LEFT);
                }
                $merged[$id] = $current;
            }
        }
        ksort($merged);
        return array_values($merged);
    }

    protected function loadOfficialWilayasFile(): array
    {
        if (!is_file($this->officialWilayasPath)) {
            return [];
        }
        $raw = @file_get_contents($this->officialWilayasPath);
        $decoded = json_decode((string)$raw, true);
        if (!is_array($decoded)) {
            return [];
        }
        $rows = $this->normalizeWilayas($decoded, 'json');
        return !empty($rows) ? $rows : [];
    }

    protected function normalizeWilayas(array $rows, string $language = 'fr'): array
    {
        $out = [];
        foreach ($rows as $row) {
            $id = null;
            $name = '';

            if (is_array($row) && array_key_exists(0, $row) && array_key_exists(1, $row)) {
                $id = (int)$row[0];
                $name = trim((string)$row[1]);
            } elseif (is_array($row)) {
                $id = isset($row['id']) ? (int)$row['id'] : null;
                $name = trim((string)($row['name'] ?? $row['label'] ?? $row['name_lt'] ?? ''));
                $arName = trim((string)($row['ar_name'] ?? ''));
            }

            if (!$id || $name === '') {
                continue;
            }

            $code = str_pad((string)($row['code'] ?? $id), 2, '0', STR_PAD_LEFT);
            $current = $out[$id] ?? ['id' => $id, 'code' => $code, 'name' => '', 'ar_name' => ''];
            if ($language === 'ar') {
                $current['ar_name'] = $name;
                if ($current['name'] === '') {
                    $current['name'] = $name;
                }
            } else {
                $current['name'] = $name;
            }
            if (!empty($arName)) {
                $current['ar_name'] = $arName;
            }
            $out[$id] = $current;
        }

        ksort($out);
        return array_values($out);
    }

    protected function normalizeCommunes(array $rows): array
    {
        $out = [];
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $id = (int)($row['id'] ?? 0);
            $name = trim((string)($row['name'] ?? $row['label'] ?? ''));
            if ($id <= 0 || $name === '') {
                continue;
            }
            $out[] = [
                'id' => $id,
                'wilaya' => (int)($row['wilaya'] ?? 0),
                'name' => $name,
                'postcode' => (string)($row['postcode'] ?? ''),
                'zone' => (string)($row['zone'] ?? ''),
            ];
        }
        return $out;
    }

    protected function normalizeText(string $value): string
    {
        $value = trim(mb_strtolower($value, 'UTF-8'));
        $value = preg_replace('/\s+/u', ' ', $value) ?? $value;
        return $value;
    }
}
