<?php

namespace Api\PhpUtils\Log;

use Api\PhpUtils\Message\Email;

class FileLog
{
    /**
     * 用于记录info级别的错误
     * 会记录请求上下文，不会发生报警邮件
     * @param string $signature 本条日志签名
     * @param string $detail_info 日志详细信息
     * @param bool $with_access_log
     */
    public static function info($signature, $detail_info = '', $with_access_log = false)
    {
        $log = 'PHP User_info: [' . $signature . ']' . ' [detail info:] ' . $detail_info;
        if ($with_access_log) {
            $log .= ' [request info:] ' . self::accessLog();
        }
        self::writeInfoLog($log);
    }

    /**
     * 用于记录waring级别的错误，在日志分析时此级别日志会使用signature进行聚合
     * 会记录请求上下文，不会发生报警邮件
     * @param string $signature 本条日志签名
     * @param string $detail_info 日志详细信息
     * @param \Exception $exception 异常信息
     */
    public static function waring($signature, $detail_info = '', $exception = null)
    {
        $log = 'PHP User_warning: [' . $signature . ']' . ' [detail info:] ' . $detail_info . ' [request info:] ' . self::accessLog();
        if ($exception != '') {
            $exception_info = 'In ' . $exception->getFile() . ' on line ' . $exception->getLine() . ' ' . $exception->getCode() . ': ' . $exception->getMessage();
            $log .= ' [exception info: ]' . $exception_info;
        }
        self::writeWarningLog($log);
    }

    /**
     * 用于记录error级别的错误,在日志分析时此级别日志会使用signatrue进行聚合
     * 会记录请求上下文，如果设置了mail_to参数会发生报警邮件
     * @param string $signature 本条日志签名
     * @param string $detail_info 日志详细信息
     * @param \Exception $exception 异常信息
     * @param array|string $mail_to 邮件接受者
     */
    public static function error($signature, $detail_info = '', $exception = null, $mail_to = '')
    {
        $log = 'PHP User_error: [' . $signature . ']' . ' [detail info:] ' . $detail_info . ' [request info:] ' . self::accessLog();
        if ($exception != '') {
            $exception_info = ' [exception info: ] In ' . $exception->getFile() . ' on line ' . $exception->getLine() . ' ' . $exception->getCode() . ': ' . $exception->getMessage();
        } else {
            $exception_info = '';
        }
        $log .= ' [exception info: ]' . $exception_info;
        error_log($log);
        if (!empty($mail_to)) {
            $subject = 'App api #' . $signature . '# ' . $_SERVER['SERVER_NAME'] . ' (' . $_SERVER['SERVER_ADDR'] . ') Alert Message';
            $body = 'Error: ' . $signature . "\n\n";
            $body .= 'Detail info: ' . $detail_info . "\n\n";
            $body .= 'Exception info: ' . $exception_info . "\n\n";
            $body .= 'Request info: ' . self::accessLog() . "\n\n";
            $body .= 'Machine: ' . gethostname();
            if (!is_array($mail_to)) {
                $mail_to = [$mail_to];
            }
            foreach ($mail_to as $mail) {
                $key = md5(sprintf("%s,%s", $mail, md5($signature)));
                if (self::shouldSendEmail($key) === true) {
                    Email::sendMail('noreply@yidian-inc.com', $mail, $subject, $body);
                }
            }
        }
    }

    private static function accessLog()
    {
        $url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME'];
        $query = http_build_query($_GET, '', '&');
        $post_data = json_encode($_POST);
        $agent = $_SERVER['HTTP_USER_AGENT'] ?? '-';
        $cookie = $_COOKIE['JSESSIONID'] ?? '-';
        return sprintf('%s?%s "%s" "%s" "%s" "%s"', $url, $query, $post_data, $agent, self::ip(), $cookie);
    }

    private static function writeInfoLog($log)
    {
        $log = '[' . date('d-M-Y H:i:s', time()) . ' ' . date_default_timezone_get() . '] ' . $log;
        $log_file = fopen(dirname(ini_get('error_log')) . '/php-infos.log', 'a+');
        fwrite($log_file, $log . "\n");
        fclose($log_file);
    }

    private static function writeWarningLog($log)
    {
        $log = '[' . date('d-M-Y H:i:s', time()) . ' ' . date_default_timezone_get() . '] ' . $log;
        $log_file = fopen(dirname(ini_get('error_log')) . '/php-warnings.log', 'a+');
        fwrite($log_file, $log . "\n");
        fclose($log_file);
    }

    private static function ip()
    {
        if (isset($_SERVER['IPV6_REMOTE_ADDR']) && !empty($_SERVER['IPV6_REMOTE_ADDR']) && trim($_SERVER['IPV6_REMOTE_ADDR']) !== '-') {  // 如果没有ipv6地址， 运维会传一个占位符“-”
            $ips = $_SERVER['IPV6_REMOTE_ADDR'];
        } elseif (!empty($_SERVER['HTTP_CDN_SRC_IP'])) {
            $ips = $_SERVER['HTTP_CDN_SRC_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ips = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ips = $_SERVER['HTTP_CLIENT_IP'];
        } else {
            $ips = $_SERVER['REMOTE_ADDR'];
        }
        $ip = explode(',', $ips);
        return $ip[0];
    }

    private static function shouldSendEmail($key)
    {
        $result = true;
//        $cache = new CommonCacheUtil(RedisUtil::CODIS_CLUSTER_ACTION);
//        if ($cache->add($key, true, 60, CacheUtil::PREFIX_SEND_MAIL) === false) {
//            $result = false;
//        }
        return $result;
    }
}
