<?php
namespace EasyChat\Library\Commerce;

abstract class AbstractCommerceContextProvider implements CommerceContextProviderInterface
{
    protected $db;
    protected $prefix;
    protected $settings;

    public function __construct($db, string $prefix, array $settings = array())
    {
        if (!preg_match('/^[A-Za-z0-9_]{0,64}$/', $prefix)) {
            throw new \InvalidArgumentException('Недопустимый префикс таблиц CMS.');
        }
        $this->db = $db;
        $this->prefix = $prefix;
        $this->settings = $settings;
    }

    protected function emails(array $lookup): array
    {
        $result = array();
        foreach (($lookup['emails'] ?? array()) as $email) {
            $email = mb_strtolower(trim((string)$email), 'UTF-8');
            if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $result[$email] = $email;
            }
        }
        return array_slice(array_values($result), 0, 6);
    }

    protected function phones(array $lookup): array
    {
        $result = array();
        foreach (($lookup['phones'] ?? array()) as $phone) {
            $digits = preg_replace('/\D+/', '', (string)$phone);
            if (strlen($digits) < 10 || strlen($digits) > 15) {
                continue;
            }
            if (strlen($digits) === 11 && $digits[0] === '8') {
                $digits = '7' . substr($digits, 1);
            }
            $variants = array($digits, '+' . $digits);
            if (strlen($digits) === 11 && $digits[0] === '7') {
                $variants[] = '8' . substr($digits, 1);
            }
            foreach ($variants as $variant) {
                $result[$variant] = $variant;
            }
        }
        return array_slice(array_values($result), 0, 12);
    }

    protected function quoted(array $values): string
    {
        if (!$values) {
            return "''";
        }
        return implode(',', array_map(function ($value) {
            return "'" . $this->db->escape((string)$value) . "'";
        }, $values));
    }

    protected function limit(int $limit): int
    {
        return max(1, min(10, $limit));
    }

    protected function money($amount, string $currency): string
    {
        $amount = is_numeric($amount) ? (float)$amount : 0.0;
        $formatted = number_format($amount, 2, ',', ' ');
        $formatted = preg_replace('/,00$/', '', $formatted);
        return trim($formatted . ' ' . strtoupper(preg_replace('/[^A-Za-zА-Яа-я₽]/u', '', $currency)));
    }

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

    protected function matched(string $id, string $kind, string $evidence, array $extra = array()): array
    {
        return array('status' => 'matched', 'reference' => array_merge(array(
            'id' => $id,
            'kind' => $kind,
            'evidence' => $evidence,
        ), $extra));
    }

    protected function unresolved(string $status): array
    {
        return array('status' => $status, 'reference' => array());
    }

    protected function rows($query): array
    {
        return is_object($query) && isset($query->rows) && is_array($query->rows) ? $query->rows : array();
    }

    protected function row($query): array
    {
        return is_object($query) && isset($query->row) && is_array($query->row) ? $query->row : array();
    }

    protected function groupItems(array $rows): array
    {
        $grouped = array();
        foreach ($rows as $row) {
            $order_id = (string)($row['order_id'] ?? '');
            if ($order_id === '') {
                continue;
            }
            $grouped[$order_id][] = array(
                'name' => $this->boundedText($row['name'] ?? '', 180),
                'quantity' => max(1, (float)($row['quantity'] ?? 1)),
                'product_id' => (string)($row['product_id'] ?? ''),
            );
        }
        return $grouped;
    }

    public function getOrder(array $customer_reference, string $order_id): array
    {
        $orders = $this->findOrders($customer_reference + array('order_id' => $order_id), 1);
        foreach ($orders as $order) {
            if ((string)($order['id'] ?? '') === $order_id) {
                return $order;
            }
        }
        return array();
    }

    public function explainIdentity(array $customer_reference): array
    {
        return array(
            'kind' => (string)($customer_reference['kind'] ?? ''),
            'evidence' => (string)($customer_reference['evidence'] ?? ''),
        );
    }
}
