<?php

namespace xmvc\libDx;

/**
 * Dx xmvc\Sqler 规则
 */
class DxSqlerExpr
{
    private static function privateGetFieldName($field)
    {
        $fieldParts = explode(".", $field);
        $result = "";
        $fieldName = DxUtils::quoteStringValue(trim($fieldParts[0]));
        if (count($fieldParts) == 2) {
            $dateProperty = trim($fieldParts[1]);
            $sqlDateFunction = "";
            $fieldPattern = "";
            switch ($dateProperty) {
                case "year":
                case "month":
                case "day":
                    $sqlDateFunction = strtoupper($dateProperty);
                    $fieldPattern = "%s(%s)";
                    break;
                case "dayOfWeek":
                    $sqlDateFunction = strtoupper($dateProperty);
                    $fieldPattern = "%s(%s) - 1";
                    break;
                default:
                    throw new \Exception("The \"" . $dateProperty . "\" command is not supported");
            }
            $result = sprintf($fieldPattern, $sqlDateFunction, $fieldName);
        } else {
            $result = $fieldName;
        }
        return $result;
    }
    private static function privateGetSimpleExpr($expression, \Closure $callback = null, $deep = 0, $index = 0)
    {
        $result = [];
        $itemsCount = count($expression);
        $fieldName = self::privateGetFieldName(trim($expression[0]));
        $op = "";
        if ($itemsCount == 2) {
            $val = $expression[1];
            $op = "=";
        } elseif ($itemsCount == 3) {
            $op = trim($expression[1]);
            $val = $expression[2];
            if (is_null($val)) {
                $val = DxUtils::quoteStringValue($val, false);
                switch ($op) {
                    case "=":
                        $op = '=';
                        break;
                    case "<>":
                        $op = '!';
                        break;
                }
            } else {
                switch ($op) {
                    case "startswith":
                        $op = "%=";
                        break;
                    case "endswith":
                        $op =  "=%";
                        break;
                    case "contains":
                        $op =  "%";
                        break;
                    case "notcontains":
                        $op =  "!%";
                        break;
                }
            }
        }
        if ($callback) {
            $callback($fieldName, $op, $val, $deep, $index);
        }
        if ($op) {
            $key = sprintf("%s{%s} #%s_%s", $fieldName, $op, $deep, $index);
            $result[$key] = $val;
        }
        return $result;
    }

    /**
     * 将 Dx Filter条件字符串规则 转 xmvc\Sqler 的 where 规则
     *
     * @param string|array $expression
     * @param \Closure|null $callback function(&$fieldName, &$op, &$value[, &$deep, &$index]) 字段名,操作符,值,递归层级,当前条件组索引, 操作符返回 '' 则废弃当前条件
     * @param integer $deep 自动
     * @param integer $index 自动
     * @return array
     */
    public static function getWhere(string|array $expression, \Closure $callback = null, int $deep = 0, int $index = 0): array
    {
        if (is_string($expression)) {
            $expression = json_decode($expression, true);
        }
        $result = [];
        $itemsCount = count($expression);
        $not = '';
        // 找 非!
        if ($itemsCount == 2 && $expression[0] == '!') {
            $not = 'NOT';
            $expression = $expression[1];
        }
        // 找 组逻辑默认 AND,  如果找到 or 则为 OR
        $groupOp = '';
        foreach ($expression as $item) {
            if ($item === 'and') {
                $groupOp = 'AND';
                break;
            } elseif ($item === 'or') {
                $groupOp = 'OR';
                break;
            }
        }
        if ($groupOp == '') {
            //单一条件
            $expression = [$expression];
            $groupOp = 'AND';
        }
        $groupKey = sprintf("%s%s #%s_%s", ($not ? $not . ' ' : ''), $groupOp, $deep, $index);
        $regI = 0;
        foreach ($expression as $item) {
            if (is_array($item)) {
                $firstValue = reset($item);
                if (is_array($firstValue)) {
                    $arr = self::getWhere($item, $callback, $deep + 1, $regI++);
                } else {
                    $arr = self::privateGetSimpleExpr($item, $callback, $deep, $regI++);
                }
                if ($arr) {
                    foreach ($arr as $k => $v) {
                        $result[$groupKey][$k] = $v;
                    }
                }
            }
        }
        return $result;
    }

    public static function getGroup(string|array $group, \Closure $callback = null): array
    {
        $result = [];
        if (is_string($group)) {
            $group = json_decode($group, false);
        }
        $tmp = DxUtils::getFieldSetBySelectors($group);
        dd($tmp);
        $tmp = explode(',', $tmp['sort']);
        foreach ($tmp as $value) {
            list($fieldName, $desc) = explode(' ', trim($value) . ' ');
            $result[$fieldName] = $desc ? 'DESC' : 'ASC';
        }
        return $result;
    }

    public static function getSort(string|array $sort, \Closure $callback = null): array
    {
        $result = [];
        if (is_string($sort)) {
            $sort = json_decode($sort, false);
        }
        $tmp = DxUtils::getFieldSetBySelectors($sort);
        $tmp = explode(',', $tmp['sort']);
        foreach ($tmp as $value) {
            list($fieldName, $desc) = explode(' ', trim($value) . ' ');
            if ($callback) {
                $callback($result, $fieldName, strtoupper($desc));
            } else {
                $result[$fieldName] = $desc ? 'DESC' : 'ASC';
            }
        }
        return $result;
    }
}
