<?php
namespace EasyChat\Library\Commerce;

use EasyChat\Library\Catalog\CmsCatalogConnectionResolver;
use EasyChat\Library\CustomerContactService;
use EasyChat\Library\Cms\CmsCustomerIdentityRepository;
use EasyChat\Library\Logger;
use EasyChat\Library\Delivery\ShipmentTrackingService;
use EasyChat\Model\Setting;

final class CustomerCommerceContextService
{
    private $registry; private $db; private $prefix;

    public function __construct($registry)
    {
        $this->registry=$registry; $this->db=$registry->get('db'); $this->prefix=easychat_db_prefix();
    }

    public function forCustomer(int $customer_id,int $limit=3,bool $force_refresh=false): array
    {
        if ($customer_id<=0) return array('status'=>'not_found','orders'=>array());
        try {
            $settings=(new Setting($this->registry))->getAll();
            $contacts=(new CustomerContactService($this->registry))->contactPointsForCustomer($customer_id);
            $lookup=array('emails'=>array(),'phones'=>array()); $confirmed=false;
            foreach($contacts as $contact){
                $type=(string)($contact['type']??'');$value=trim((string)($contact['value']??''));
                if($value===''||!isset($lookup[$type.'s']))continue;
                $lookup[$type.'s'][]=$value;
                if(in_array((string)($contact['status']??''),array(CustomerContactService::STATUS_OPERATOR_CONFIRMED,CustomerContactService::STATUS_PROVIDER_CONFIRMED),true))$confirmed=true;
            }
            $edition=defined('EASYCHAT_CMS_EDITION')?(string)EASYCHAT_CMS_EDITION:'';
            $connection=CmsCatalogConnectionResolver::resolve($this->db,$settings,$edition);
            $cms_identity=array();
            if(!empty($connection['ready'])){
                $scope=(string)$connection['type'].'|'.(string)$connection['prefix'];
                $cms_identity=(new CmsCustomerIdentityRepository($this->db,$this->prefix,(string)($settings['chat_install_secret']??'')))->forCustomer($customer_id,(string)$connection['type'],$scope);
                $cms_subject=trim((string)($cms_identity['subject']??''));
                $cms_subject_kind=$this->cmsSubjectKind((string)$connection['type']);
                if($cms_subject===''||$cms_subject_kind==='')$cms_identity=array();
            }
            if(!$lookup['emails']&&!$lookup['phones']&&!$cms_identity)return array('status'=>'not_found','orders'=>array());
            if($cms_identity)$lookup['cms_identity']=array('provider'=>(string)$cms_identity['provider'],'subject_hash'=>(string)$cms_identity['subject_hash']);
            $cache = new CommerceContextCache();
            $cache_key = $cache->key($customer_id, $lookup, $limit, $settings);
            if ($force_refresh && !$cache->claimRefresh($cache_key)) {
                $force_refresh = false;
            }
            $cached = $force_refresh ? array() : $cache->get($cache_key);
            if ($cached) {
                $result = (array)$cached['value'];
                $result['cache'] = array('hit' => true, 'stale' => !empty($cached['cache_stale']), 'age' => (int)($cached['cache_age'] ?? 0));
                return $result;
            }
            $stale_cached = $force_refresh ? array() : $cache->get($cache_key, true);
            $orders=array();$sources=array();$identity=array();$provider_type='';$provider_label='';$ai_allowed=$confirmed;
            $normalizer = new CommerceContextNormalizer(new ShipmentTrackingService($this->registry));

             
             
            if(!empty($connection['ready'])){
                $provider=CommerceProviderFactory::create($this->db,(string)$connection['type'],(string)$connection['prefix'],$settings);
                if($provider){
                    $scope=(string)$connection['type'].'|'.(string)$connection['prefix'];
                    $repo=new CommerceIdentityRepository($this->db,$this->prefix,(string)($settings['chat_install_secret']??''));
                    $reference=$cms_identity ? array('id'=>$cms_subject,'kind'=>$cms_subject_kind,'evidence'=>'cms_session','confidence'=>'confirmed') : array();
                    $from_projection=!empty($reference);
                    if(!$reference)$reference=$repo->find($customer_id,(string)$connection['type'],$scope,$lookup);
                    $from_projection=$from_projection||!empty($reference);
                    if(!$reference){$resolved=$provider->resolveCustomer($lookup);if(($resolved['status']??'')==='matched'){$reference=(array)($resolved['reference']??array());$repo->save($customer_id,(string)$connection['type'],$scope,$reference,$lookup,$confirmed?'confirmed':'unique_exact');}}
                    if($reference){$provider_type=(string)$connection['type'];$provider_label=$this->providerLabel($provider_type);$source_ai_allowed=$ai_allowed||($from_projection&&($reference['confidence']??'')==='confirmed');$cms_orders=$normalizer->orders($provider->findOrders($reference,$limit),$provider_type,$provider_label,$source_ai_allowed,$force_refresh);$orders=$cms_orders;$sources[]=array('provider'=>$provider_type,'label'=>$provider_label,'orders'=>$cms_orders,'observed_at'=>gmdate('c'));$identity=$provider->explainIdentity($reference);$ai_allowed=$source_ai_allowed;}
                }
            }
            $moysklad=$this->moySkladContext($settings,$lookup,$limit,$confirmed,$normalizer,$force_refresh);
            if(($moysklad['status']??'')==='ready'){
                $sources[]=$moysklad;
                foreach((array)$moysklad['orders'] as $order)$orders[]=$order;
                $orders=array_slice($orders,0,10);
            }
            if(!$sources){
                if($stale_cached){
                    $result=(array)$stale_cached['value'];
                    $result['cache']=array('hit'=>true,'stale'=>true,'age'=>(int)($stale_cached['cache_age']??0));
                    return $result;
                }
                return array('status'=>(string)($moysklad['status']??'unavailable'),'orders'=>array());
            }
            if(count($sources)>1)$provider_label=implode(' + ',array_map(function($source){return(string)($source['label']??'');},$sources));
            $result = array(
                'status'=>'ready','provider'=>$provider_type?:'moysklad','provider_label'=>$provider_label?:'МойСклад',
                'orders'=>$orders,'order_count'=>count($orders),'sources'=>$sources,'ai_allowed'=>$ai_allowed,
                'identity'=>$identity?:((array)($moysklad['identity']??array())),
                'context_version'=>2,'generated_at'=>gmdate('c'),'fresh_for_seconds'=>300,
            );
            $result['cache'] = array('hit' => false, 'stale' => false, 'age' => 0);
            if ($sources) {
                $cache->put($cache_key, $result);
            }
            return $result;
        }catch(\Throwable $e){
            Logger::warning('commerce_context_failed fingerprint='.substr(hash('sha256',$e->getMessage()),0,12),'commerce.log');
            if(isset($stale_cached)&&$stale_cached){
                $result=(array)$stale_cached['value'];
                $result['cache']=array('hit'=>true,'stale'=>true,'age'=>(int)($stale_cached['cache_age']??0));
                return $result;
            }
            return array('status'=>'unavailable','orders'=>array());
        }
    }

    public function promptForCustomer(int $customer_id): string
    {
        $context=$this->forCustomer($customer_id,3);
        if(($context['status']??'')!=='ready'||empty($context['ai_allowed'])||empty($context['orders']))return '';
        $lines=array('Заказы клиента (точное сопоставление):');
        foreach($context['orders'] as $order){
            $source=(string)($order['source_label']??(($order['source']??'')==='moysklad'?'МойСклад':'CMS'));
            $line='- ['.$source.'] №'.$order['number'].' · '.$order['date'].' · '.$order['status'].' · '.$order['total'];
            $items=array();foreach(array_slice($order['items'],0,6)as$item){$label=$item['name'].' × '.$item['quantity'];if(isset($item['stock'])&&$item['stock']!==null)$label.=' (остаток '.$item['stock'].')';$items[]=$label;}
            if($items)$line.=' · товары: '.implode(', ',$items);
            foreach(array_slice((array)($order['shipments']??array()),0,2)as$shipment){if(($shipment['status_label']??'')!=='')$line.=' · доставка: '.$shipment['status_label'].(($shipment['updated_at']??'')!==''?' ('.$shipment['updated_at'].')':'');}
            $lines[]=$line;
        }
        return mb_substr(implode("\n",$lines),0,1600,'UTF-8');
    }

    private function moySkladContext(array $settings,array $lookup,int $limit,bool $confirmed,CommerceContextNormalizer $normalizer,bool $force_refresh=false): array
    {
        if((string)($settings[MoySkladConnection::ENABLED]??'0')!=='1')return array('status'=>'disabled');
        try{
            $connection=new MoySkladConnection($this->registry);$state=$connection->publicState();$provider=new MoySkladCommerceContextProvider($connection->client(),(array)($state['field_mapping']??array()));
            $resolved=$provider->resolveCustomer($lookup);if(($resolved['status']??'')!=='matched')return array('status'=>(string)($resolved['status']??'unavailable'));
            $orders=$normalizer->orders($provider->findOrders((array)$resolved['reference'],$limit),'moysklad','МойСклад',$confirmed,$force_refresh);
            return array('status'=>'ready','provider'=>'moysklad','label'=>'МойСклад','orders'=>$orders,'ai_allowed'=>$confirmed,'identity'=>$provider->explainIdentity((array)$resolved['reference']),'observed_at'=>gmdate('c'));
        }catch(\Throwable $e){Logger::warning('moysklad_context_failed fingerprint='.substr(hash('sha256',$e->getMessage()),0,12),'commerce.log');return array('status'=>'unavailable');}
    }

    private function plain($value,int $limit): string{return mb_substr(trim(preg_replace('/\s+/u',' ',strip_tags((string)$value))),0,$limit,'UTF-8');}
    private function providerLabel(string $type): string{return array('opencart'=>'OpenCart','wordpress'=>'WooCommerce','webasyst'=>'Shop-Script','bitrix'=>'1С-Битрикс')[$type]??'CMS';}
    private function cmsSubjectKind(string $type): string{return array('opencart'=>'customer_id','wordpress'=>'customer_id','webasyst'=>'contact_id','bitrix'=>'user_id')[$type]??'';}
}
