<?php
namespace EasyChat\Library\Commerce;

use EasyChat\Library\Messenger\SecretBox;
use EasyChat\Model\Setting;

final class MoySkladConnection
{
    public const ENABLED = 'chat_moysklad_enabled';
    public const TOKEN = 'chat_moysklad_token';
    public const FIELD_MAPPING = 'chat_moysklad_field_mapping';
    private $registry;
    private $settings;

    public function __construct($registry)
    {
        $this->registry = $registry;
        $this->settings = new Setting($registry);
    }

    public function publicState(): array
    {
        $all = $this->settings->getAll();
        $token = $this->decrypt((string)($all[self::TOKEN] ?? ''));
        return array(
            'enabled' => (string)($all[self::ENABLED] ?? '0') === '1',
            'token_saved' => $token !== '',
            'token_mask' => SecretBox::mask($token),
            'last_check_at' => (string)($all['chat_moysklad_last_check_at'] ?? ''),
            'last_error' => (string)($all['chat_moysklad_last_error'] ?? ''),
            'field_mapping' => $this->mapping((string)($all[self::FIELD_MAPPING] ?? '')),
        );
    }

    public function save(bool $enabled, string $token): array
    {
        $all = $this->settings->getAll();
        $current = (string)($all[self::TOKEN] ?? '');
        if (trim($token) !== '') {
            $current = SecretBox::encrypt(trim($token), $this->secret($all));
        }
        if ($enabled && $this->decrypt($current) === '') {
            throw new \InvalidArgumentException('moysklad_token_required');
        }
        $this->settings->setManyAtomic(array(
            self::ENABLED => $enabled ? '1' : '0',
            self::TOKEN => $current,
        ));
        return $this->publicState();
    }

    public function saveMapping(array $mapping): array
    {
        $clean = array();
        foreach (array('carrier','tracking_number','apiship_client_number','apiship_order_id','provider_number') as $key) {
            $value = preg_replace('/[^0-9a-f-]/i', '', (string)($mapping[$key] ?? ''));
            if (preg_match('/^[0-9a-f-]{30,40}$/i', $value)) $clean[$key] = strtolower($value);
        }
        $this->settings->setManyAtomic(array(self::FIELD_MAPPING => json_encode($clean, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)));
        return $this->publicState();
    }

    private function mapping(string $raw): array
    {
        $decoded = json_decode($raw, true);
        return is_array($decoded) ? $decoded : array();
    }

    public function client(): MoySkladClient
    {
        $all = $this->settings->getAll();
        return new MoySkladClient(
            $this->registry,
            $this->decrypt((string)($all[self::TOKEN] ?? ''))
        );
    }

    public function recordCheck(bool $ok, string $error = ''): void
    {
        $this->settings->setMany(array(
            'chat_moysklad_last_check_at' => date('Y-m-d H:i:s'),
            'chat_moysklad_last_error' => $ok ? '' : substr($error, 0, 120),
        ));
    }

    private function decrypt(string $value): string
    {
        return SecretBox::decrypt($value, $this->secret($this->settings->getAll()));
    }

    private function secret(array $all): string
    {
        $secret = trim((string)($all['chat_install_secret'] ?? ''));
        if ($secret === '') {
            throw new \RuntimeException('install_secret_required');
        }
        return $secret;
    }
}
