<?php

namespace Application\Service\Extension\Helper;

use Application\Service\DB\Dictionary\FormField;
use Application\Service\Exceptions\InvalidArgumentException;
use Application\Service\Extension\Laminas;

/**
 * 前端传过来的数据一些处理方法
 */
class DataHelper
{

    protected static array $isField = [];

    /**
     * 处理表单数据
     * 如果是json类型的, 会把json数据处理成数组
     * @param array $postData
     * @param int|null $formId
     * @return array
     */
    public static function handleFormData(array $postData, int $formId = null): array
    {
        $versionData = [];
        if ($formId) {
            $versionData = StringHelper::jsonDecode(Laminas::$serviceManager->itemFormVersion->fetchOne([
                'where' => ['form_id' => $formId]
            ])['field'], false);
        }

        foreach ($postData as $key => $datum) {
            // 如果有`,`, 并且不是json格式。前端传图会传json格式
            if (stripos($datum, ',') !== false && StringHelper::jsonDecode($datum, false) === false) {
                $type = $versionData[self::getFieldId($key)]['type'] ?? false;
                // 多选需要分割成数组
                if ($type == FormField::FORM_FIELD_TYPE_CHECKBOX) {
                    $postData[$key] = explode(',', $datum);
                }
            }
        }

        return $postData;
    }

    /**
     * 获取字段id
     * @param $string
     * @return mixed|string
     */
    public static function getFieldId($string)
    {
        return explode('-', $string)[0];
    }

    /**
     * 判断数据是否是表单字段
     * @param string $str
     * @return bool
     */
    public static function isField(string $str): bool
    {
        if (isset(self::$isField[$str])) {
            return self::$isField[$str];
        }

        if (is_numeric($str)) {
            self::$isField[$str] = true;
            return true;
        }

        self::$isField[$str] = is_numeric(strtr($str, ['-' => '']));
        return self::$isField[$str];
    }

    public static function getUrlQueryWithoutParams(string $url): string
    {
        if (stripos($url, 'http') === false) {
            return trim($url, '/');
        }

        $parseUrl = parse_url($url);
        return strtr($parseUrl['query'], ['path=' => '', '&style=thumb' => '']);
    }

    /**
     * 处理图片路径
     */
    public static function handleImageSrc(?string $src): string
    {
        if ($src === null) return '';

        if (stripos($src, 'blob:') !== false) {
            $src = strtr($src, [
                'blob:' => ''
            ]);
        }

        if (stripos($src, 'http') !== false) {
            if ($parsedUrl = parse_url($src)) {
                extract($parsedUrl);
            }
        }

        if (stripos($query ?: $src, '&') !== false || stripos($query ?: $src, '?') !== false) {
            preg_match('/(upload.*?)[\&\?]/', $query ?: $src, $pregArr);
            $query = $pregArr[1] ?? null;
        }


        if (!$query) {
            throw new InvalidArgumentException('图片链接解析失败。');
        }

        if (stripos($src, 'bucket') !== false) {
            parse_str($src, $handleVal);
            $query .= "&bucket={$handleVal['bucket']}";
        }

        if (stripos($src, 'style') !== false) {
            parse_str($src, $handleVal);
            $query = strtr($query, ["&style={$handleVal['style']}" => '']);
        }

        return strtr($query, [
            'path=' => ''
        ]);
    }

    /**
     * 根据日期类型返回默认的日期格式字符串
     *
     * 此函数旨在为不同的日期类型提供标准化的日期字符串格式它根据输入的日期类型，
     * 返回相应格式的当前日期字符串如果输入的日期类型不匹配任何预定义类型，
     * 则返回空字符串此函数有助于在表单字段中统一日期格式的处理
     *
     * @param string $dateType 日期类型标识符，用于决定返回的日期格式
     * @return string 根据日期类型格式化的当前日期字符串，或者如果类型不匹配则返回空字符串
     */
    public static function getDateDefault($dateType): string
    {
        // 检查是否为DateTime类型，如果是，则返回包括时间的日期字符串
        if (in_array($dateType, [FormField::FORM_FIELD_TYPE_DATETIME, 'DateTime'])) {
            return date('Y-m-d H:i:s');
        } elseif (in_array($dateType, [FormField::FORM_FIELD_TYPE_DATE, 'Date'])) {
            // 检查是否为Date类型，如果是，则返回不包括时间的日期字符串
            return date('Y-m-d');
        }

        // 如果日期类型不匹配任何已知类型，返回空字符串
        return '';
    }

    /**
     * 生成MD5哈希值
     *
     * 该方法接受一个数据参数，可以是字符串或数组，并返回其MD5哈希值
     * 如果数据类型是字符串，直接返回其MD5哈希值
     * 如果数据类型是数组，将数组的每个键值对序列化后分批次更新到哈希上下文中，最后返回综合哈希值
     * 不支持的类型将抛出异常
     *
     * @param mixed $data 要生成MD5哈希值的数据，可以是字符串或数组
     * @return string MD5哈希值
     * @throws \Exception 如果数据类型既不是字符串也不是数组，则抛出异常
     */
    public static function md5($data): string
    {
        // 检查数据是否为字符串
        if (is_string($data)) {
            return md5($data);
        } elseif (is_array($data)) {
            // 初始化MD5哈希上下文
            $hashContext = hash_init('md5');
            // 遍历数组，将每个键值对序列化后分批次更新到哈希上下文中
            foreach ($data as $key => $value) {
                hash_update($hashContext, $key . serialize($value));  // 分批次加入键值
            }

            // 计算最终哈希
            return hash_final($hashContext);
        }

        // 如果数据类型既不是字符串也不是数组，抛出异常
        throw new \Exception('暂不支持的类型。');
    }

    /**
     * 检查给定的数据数组是否为空
     * 此方法用于验证在给定的数组中，所有被认为是字段的项是否都为空
     * 它主要用于确定一个数据表单或数据集是否完全未填写或未设置
     *
     * @param array $data 包含要检查的字段的数组
     * @return bool 如果所有字段都为空，则返回true；如果有任何字段不为空，则返回false
     */
    public static function isEmpty(array $data)
    {
        // 遍历数组中的每个元素
        foreach ($data as $k => $item) {
            // 如果当前键不是字段，则跳过此项
            if (!self::isField($k)) {
                continue;
            }

            // 如果当前字段不为空，则整个数据不为空，返回false
            if ($item !== '') {
                return false;
            }
        }

        // 所有字段都为空，返回true
        return true;
    }

    /**
     * @note 转换选项字段
     * @param array $tableDataList
     * @param array $tableColumnList
     * @return void
     */
    public static function exchangeOptionToText(array &$tableDataList, array &$tableColumnList) {
        $formCheckFieldTypeList = ['Radio' => 'radios', 'Checkbox' => 'checkboxs', 'Select' => 'options', 'RadioRadio' => 'radios', 'Switch' => 'switchs'];
        if (! empty($tableColumnList) && ! empty($tableDataList)) {
            foreach ($tableColumnList as &$column) {
                if ( ! in_array($column['type'], array_keys($formCheckFieldTypeList))) continue;

                foreach($tableDataList as &$tableRow) {
                    array_walk($column[$formCheckFieldTypeList[$column['type']]], function($option) use(&$tableRow, &$column) {

                        if($tableRow[$column['prop']] == $option['value']) $tableRow[$column['prop']] = $option['label'];
                    });
                }
            }
        }
    }
}