<?php
namespace EasyChat\Controller;

use EasyChat\Library\Commerce\MoySkladConnection;
use EasyChat\Library\RequestContext;

final class MoyskladIntegration extends Base
{
    public function __construct($registry)
    {
        parent::__construct($registry);
        $session = RequestContext::session();
        if (empty($session['manager_id']) || ($session['manager_role'] ?? '') !== 'admin') {
            $this->json(403, array('success' => false, 'error' => 'Недостаточно прав.'));
        }
    }

    public function save(): void
    {
        $this->postAndNonce();
        $post = RequestContext::post();
        try {
            $state = (new MoySkladConnection($this->registry))->save(
                !empty($post['enabled']),
                (string)($post['token'] ?? '')
            );
            $this->json(200, array(
                'success' => true,
                'message' => !empty($state['enabled']) ? 'МойСклад подключён.' : 'Интеграция выключена.',
                'state' => $state,
                'nonce' => $this->nonce(),
            ));
        } catch (\InvalidArgumentException $e) {
            $this->json(422, array('success' => false, 'error' => 'Добавьте токен МойСклад.', 'nonce' => $this->nonce()));
        } catch (\Throwable $e) {
            $this->json(500, array('success' => false, 'error' => 'Не удалось сохранить подключение.', 'nonce' => $this->nonce()));
        }
    }

    public function test(): void
    {
        $this->postAndNonce();
        $connection = new MoySkladConnection($this->registry);
        try {
            $result = $connection->client()->test();
            if (empty($result['success'])) {
                throw new \RuntimeException('moysklad_invalid_response');
            }
            $connection->recordCheck(true);
            $this->json(200, array(
                'success' => true,
                'message' => 'МойСклад отвечает. Доступ к клиентам и заказам подтверждён.',
                'account' => (string)($result['account'] ?? ''),
                'nonce' => $this->nonce(),
            ));
        } catch (\Throwable $e) {
            $connection->recordCheck(false, $e->getMessage());
            $this->json(502, array(
                'success' => false,
                'error' => $this->friendly($e->getMessage()),
                'nonce' => $this->nonce(),
            ));
        }
    }

    public function discover(): void
    {
        $this->postAndNonce();
        try {
            $client = (new MoySkladConnection($this->registry))->client();
            $result = array();
            foreach (array('customerorder','demand') as $entity) {
                foreach ($client->metadata($entity) as $attribute) {
                    $href=(string)($attribute['meta']['href']??'');
                    $id=(string)($attribute['id']??'');
                    if ($id === '' && preg_match('~/attributes/([0-9a-f-]{30,40})$~i',$href,$m)) $id=$m[1];
                    if (!preg_match('/^[0-9a-f-]{30,40}$/i',$id)) continue;
                    $name=$this->plain((string)($attribute['name']??''),80);
                    $result[] = array('entity'=>$entity,'id'=>strtolower($id),'name'=>$name,'type'=>(string)($attribute['type']??''),'suggested'=>$this->suggestedMapping($name));
                }
            }
            $this->json(200,array('success'=>true,'attributes'=>$result,'nonce'=>$this->nonce()));
        } catch (\Throwable $e) { $this->json(502,array('success'=>false,'error'=>'Не удалось получить дополнительные поля МойСклад.','nonce'=>$this->nonce())); }
    }

    public function saveMapping(): void
    {
        $this->postAndNonce();
        $raw=(string)(RequestContext::post()['mapping']??''); $mapping=json_decode($raw,true);
        if (!is_array($mapping)) $mapping=array();
        try { $state=(new MoySkladConnection($this->registry))->saveMapping($mapping); $this->json(200,array('success'=>true,'message'=>'Сопоставление сохранено.','state'=>$state,'nonce'=>$this->nonce())); }
        catch (\Throwable $e) { $this->json(422,array('success'=>false,'error'=>'Не удалось сохранить сопоставление.','nonce'=>$this->nonce())); }
    }

    private function postAndNonce(): void
    {
        if (RequestContext::method() !== 'POST') {
            $this->json(405, array('success' => false, 'error' => 'Метод не поддерживается.'));
        }
        $expected = (string)(RequestContext::session()['easychat_moysklad_nonce'] ?? '');
        $actual = (string)(RequestContext::post()['nonce'] ?? '');
        if ($expected === '' || $actual === '' || !hash_equals($expected, $actual)) {
            $this->json(403, array(
                'success' => false,
                'error' => 'Сессия устарела. Обновите страницу.',
                'nonce' => $this->nonce(),
            ));
        }
    }

    private function nonce(): string
    {
        $session =& RequestContext::session();
        if (empty($session['easychat_moysklad_nonce'])) {
            $session['easychat_moysklad_nonce'] = bin2hex(random_bytes(16));
        }
        return (string)$session['easychat_moysklad_nonce'];
    }

    private function friendly(string $code): string
    {
        if ($code === 'moysklad_credentials_invalid') {
            return 'МойСклад отклонил токен. Создайте новый токен и проверьте права чтения.';
        }
        if ($code === 'moysklad_rate_limited') {
            return 'МойСклад временно ограничил запросы. Повторите проверку через минуту.';
        }
        return 'МойСклад сейчас не ответил. Проверьте доступ сервера к api.moysklad.ru и повторите.';
    }

    private function plain(string $value,int $limit): string { return mb_substr(trim(preg_replace('/\s+/u',' ',strip_tags($value))),0,$limit,'UTF-8'); }

    private function suggestedMapping(string $name): string
    {
        $name=mb_strtolower($name,'UTF-8');
        if (preg_match('/api.?ship.*(client|клиент)|client.?number|номер.*api.?ship/u',$name)) return 'apiship_client_number';
        if (preg_match('/api.?ship.*(order|заказ)|order.?id|ид.*заказ/u',$name)) return 'apiship_order_id';
        if (preg_match('/перевоз|служб.*достав|достав.*служб|carrier/u',$name)) return 'carrier';
        if (preg_match('/трек|tracking|отправлен.*номер|номер.*отправ/u',$name)) return 'tracking_number';
        if (preg_match('/провайдер.*номер|provider.*number/u',$name)) return 'provider_number';
        return '';
    }

    private function json(int $status, array $data): void
    {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        header('Cache-Control: no-store');
        echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }
}
