<?php

namespace App\Http\Controllers\Admin\Config;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class ServerController extends Controller
{
    public function index()
    {
        $this->server();
    }

    /**
     * 서버 상태
     * @method GET
     * @see /admin/config/server
     */
    public function server()
    {
        // 서버 자원 정보
        return view('admin.config.server.index', [
            'subject' => '서버상태',
            'networkInfo' => $this->getNetworkInfo(),
            'memInfo' => $this->getMemoryInfo(),
            'cpuInfo' => $this->getCpuInfo(),
            'sysInfo' => $this->getSysInfo(),
            'os' => explode(" ", php_uname()) // 서버 운영체제 정보
        ]);
    }

    /**
     * 관리자 페이지 메인 ajax 호출
     */
    public function ajaxData(Request $request)
    {
        if (!$request->ajax()) {
            exit('No direct script access allowed');
        }

        $sysInfo = $this->getSysInfo();

        echo json_encode([
            'networkInfo' => $this->getNetworkInfo(),
            'sysInfo' => $sysInfo,
            'upTime' => $sysInfo['uptime'],
            'sTime' => date('Y-m-d H:i:s'),
            'cpuInfo' => $this->getCpuInfo(),
            'memInfo' => $this->getMemoryInfo()
        ]);
    }

    /**
     * 운영체제 및 서버 시스템 정보
     */
    private function getSysInfo()
    {
        $sysInfo = [null];
        switch (PHP_OS) {
            case "Linux":

                // CPU
                if (false === ($str = @file("/proc/cpuinfo"))) {
                    return false;
                }
                $str = implode("", $str);

                @preg_match_all("/model\s+name\s{0,}\:+\s{0,}([\w\s\)\(\@.-]+)([\r\n]+)/s", $str, $model);
                @preg_match_all("/cpu\s+MHz\s{0,}\:+\s{0,}([\d\.]+)[\r\n]+/", $str, $mhz);
                @preg_match_all("/cache\s+size\s{0,}\:+\s{0,}([\d\.]+\s{0,}[A-Z]+[\r\n]+)/", $str, $cache);
                @preg_match_all("/bogomips\s{0,}\:+\s{0,}([\d\.]+)[\r\n]+/", $str, $bogomips);

                if (false !== is_array($model[1])) {
                    $sysInfo['cpu']['num'] = sizeof($model[1]);

                    for ($i = 0; $i < $sysInfo['cpu']['num']; $i++) {
                        $sysInfo['cpu']['model'][] = $model[1][$i] . '&nbsp;(' . $mhz[1][$i] . ')';
                        $sysInfo['cpu']['mhz'][] = $mhz[1][$i];
                        $sysInfo['cpu']['cache'][] = $cache[1][$i];
                        $sysInfo['cpu']['bogomips'][] = $bogomips[1][$i];
                    }

                    if ($sysInfo['cpu']['num'] == 1) {
                        $x1 = '';
                    } else {
                        $x1 = ' Г—' . $sysInfo['cpu']['num'];
                    }

                    $mhz[1][0] = ' | Frequency:' . $mhz[1][0];
                    $cache[1][0] = ' | Secondary cache:' . $cache[1][0];
                    $bogomips[1][0] = ' | Bogomips:' . $bogomips[1][0];
                    $sysInfo['cpu']['model'][] = $model[1][0] . $mhz[1][0] . $cache[1][0] . $bogomips[1][0] . $x1;
                    if (false !== is_array($sysInfo['cpu']['model'])) $sysInfo['cpu']['model'] = implode("<br />", $sysInfo['cpu']['model']);
                    if (false !== is_array($sysInfo['cpu']['mhz'])) $sysInfo['cpu']['mhz'] = implode("<br />", $sysInfo['cpu']['mhz']);
                    if (false !== is_array($sysInfo['cpu']['cache'])) $sysInfo['cpu']['cache'] = implode("<br />", $sysInfo['cpu']['cache']);
                    if (false !== is_array($sysInfo['cpu']['bogomips'])) $sysInfo['cpu']['bogomips'] = implode("<br />", $sysInfo['cpu']['bogomips']);
                }

                // NETWORK, UPTIME
                if (false === ($str = @file("/proc/uptime"))) {
                    return false;
                }
                $str = explode(" ", implode("", $str));
                $str = trim($str[0]);
                $min = $str / 60;
                $hours = $min / 60;
                $days = floor($hours / 24);
                $hours = floor($hours - ($days * 24));
                $min = floor($min - ($days * 60 * 24) - ($hours * 60));
                if ($days !== 0) $sysInfo['uptime'] = $days . " Day";
                if ($hours !== 0) $sysInfo['uptime'] .= $hours . " Hour";
                $sysInfo['uptime'] .= $min . " Minute";

                // MEMORY
                if (false === ($str = @file("/proc/meminfo"))) {
                    return false;
                }
                $str = implode("", $str);
                preg_match_all("/MemTotal\s{0,}\:+\s{0,}([\d\.]+).+?MemFree\s{0,}\:+\s{0,}([\d\.]+).+?Cached\s{0,}\:+\s{0,}([\d\.]+).+?SwapTotal\s{0,}\:+\s{0,}([\d\.]+).+?SwapFree\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buf);
                preg_match_all("/Buffers\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buffers);
                $sysInfo['memTotal'] = round($buf[1][0] / 1024, 2);
                $sysInfo['memFree'] = round($buf[2][0] / 1024, 2);
                $sysInfo['memBuffers'] = round($buffers[1][0] / 1024, 2);
                $sysInfo['memCached'] = round($buf[3][0] / 1024, 2);
                $sysInfo['memUsed'] = $sysInfo['memTotal'] - $sysInfo['memFree'];
                $sysInfo['memPercent'] = (floatval($sysInfo['memTotal']) != 0) ? round($sysInfo['memUsed'] / $sysInfo['memTotal'] * 100, 2) : 0;
                $sysInfo['memRealUsed'] = $sysInfo['memTotal'] - $sysInfo['memFree'] - $sysInfo['memCached'] - $sysInfo['memBuffers'];
                $sysInfo['memRealFree'] = $sysInfo['memTotal'] - $sysInfo['memRealUsed'];
                $sysInfo['memRealPercent'] = (floatval($sysInfo['memTotal']) != 0) ? round($sysInfo['memRealUsed'] / $sysInfo['memTotal'] * 100, 2) : 0;
                $sysInfo['memCachedPercent'] = (floatval($sysInfo['memCached']) != 0) ? round($sysInfo['memCached'] / $sysInfo['memTotal'] * 100, 2) : 0;
                $sysInfo['swapTotal'] = round($buf[4][0] / 1024, 2);
                $sysInfo['swapFree'] = round($buf[5][0] / 1024, 2);
                $sysInfo['swapUsed'] = round($sysInfo['swapTotal'] - $sysInfo['swapFree'], 2);
                $sysInfo['swapPercent'] = (floatval($sysInfo['swapTotal']) != 0) ? round($sysInfo['swapUsed'] / $sysInfo['swapTotal'] * 100, 2) : 0;

                // LOAD AVG
                if (false === ($str = @file("/proc/loadavg"))) {
                    return false;
                }
                $str = explode(" ", implode("", $str));
                $str = array_chunk($str, 4);
                $sysInfo['loadAvg'] = implode(" ", $str[0]);
                break;

            case "FreeBSD":

                // CPU
                if (false === ($sysInfo['cpu']['num'] = getKey("hw.ncpu"))) {
                    return false;
                }
                $sysInfo['cpu']['model'] = getKey("hw.model");

                // LOAD AVG
                if (false === ($sysInfo['loadAvg'] = getKey("vm.loadavg"))) {
                    return false;
                }

                // UPTIME
                if (false === ($buf = getKey("kern.boottime"))) {
                    return false;
                }
                $buf = explode(' ', $buf);
                $sys_ticks = time() - intval($buf[3]);
                $min = $sys_ticks / 60;
                $hours = $min / 60;
                $days = floor($hours / 24);
                $hours = floor($hours - ($days * 24));
                $min = floor($min - ($days * 60 * 24) - ($hours * 60));
                if ($days !== 0) $sysInfo['uptime'] = $days . " Day";
                if ($hours !== 0) $sysInfo['uptime'] .= $hours . " Hour";
                $sysInfo['uptime'] .= $min . " Minute";

                // MEMORY
                if (false === ($buf = getKey("hw.physmem"))) {
                    return false;
                }

                $sysInfo['memTotal'] = round($buf / 1024 / 1024, 2);
                $str = getKey("vm.vmtotal");
                preg_match_all("/\nVirtual Memory[\:\s]*\(Total[\:\s]*([\d]+)K[\,\s]*Active[\:\s]*([\d]+)K\)\n/i", $str, $buff, PREG_SET_ORDER);
                preg_match_all("/\nReal Memory[\:\s]*\(Total[\:\s]*([\d]+)K[\,\s]*Active[\:\s]*([\d]+)K\)\n/i", $str, $buf, PREG_SET_ORDER);
                $sysInfo['memRealUsed'] = round($buf[0][2] / 1024, 2);
                $sysInfo['memCached'] = round($buff[0][2] / 1024, 2);
                $sysInfo['memUsed'] = round($buf[0][1] / 1024, 2) + $sysInfo['memCached'];
                $sysInfo['memFree'] = $sysInfo['memTotal'] - $sysInfo['memUsed'];
                $sysInfo['memPercent'] = (floatval($sysInfo['memTotal']) != 0) ? round($sysInfo['memUsed'] / $sysInfo['memTotal'] * 100, 2) : 0;
                $sysInfo['memRealPercent'] = (floatval($sysInfo['memTotal']) != 0) ? round($sysInfo['memRealUsed'] / $sysInfo['memTotal'] * 100, 2) : 0;
                break;

            default:
                break;
        }

        if(in_array(PHP_OS, ['Linux', 'FreeBSD'])) {
            if ($sysInfo['memTotal'] < 1024) {
                $memTotal = $sysInfo['memTotal'] . " M";
                $mt = $sysInfo['memTotal'] . " M";
                $mu = $sysInfo['memUsed'] . " M";
                $mf = $sysInfo['memFree'] . " M";
                $mc = $sysInfo['memCached'] . " M";
                $mb = $sysInfo['memBuffers'] . " M";
                $st = $sysInfo['swapTotal'] . " M";
                $su = $sysInfo['swapUsed'] . " M";
                $sf = $sysInfo['swapFree'] . " M";
                $swapPercent = ($sysInfo['swapPercent']);
                $memRealUsed = $sysInfo['memRealUsed'] . " M";
                $memRealFree = $sysInfo['memRealFree'] . " M";
                $memRealPercent = ($sysInfo['memRealPercent']);
                $memPercent = ($sysInfo['memPercent']);
                $memCachedPercent = ($sysInfo['memCachedPercent']);
            } else {
                $memTotal = round($sysInfo['memTotal'] / 1024, 3) . " G";
                $mt = round($sysInfo['memTotal'] / 1024, 3) . " G";
                $mu = round($sysInfo['memUsed'] / 1024, 3) . " G";
                $mf = round($sysInfo['memFree'] / 1024, 3) . " G";
                $mc = round($sysInfo['memCached'] / 1024, 3) . " G";
                $mb = round($sysInfo['memBuffers'] / 1024, 3) . " G";
                $st = round($sysInfo['swapTotal'] / 1024, 3) . " G";
                $su = round($sysInfo['swapUsed'] / 1024, 3) . " G";
                $sf = round($sysInfo['swapFree'] / 1024, 3) . " G";
                $swapPercent = ($sysInfo['swapPercent']);
                $memRealUsed = round($sysInfo['memRealUsed'] / 1024, 3) . " G";
                $memRealFree = round($sysInfo['memRealFree'] / 1024, 3) . " G";
                $memRealPercent = ($sysInfo['memRealPercent']);
                $memPercent = ($sysInfo['memPercent']);
                $memCachedPercent = ($sysInfo['memCachedPercent']);
            }

            $sysInfo = array_merge($sysInfo, [
                'memTotal' => $memTotal,
                'mt' => $mt,
                'mu' => $mu,
                'mf' => $mf,
                'mc' => $mc,
                'mb' => $mb,
                'st' => $st,
                'su' => $su,
                'sf' => $sf,
                'swapPercent' => $swapPercent,
                'memRealUsed' => $memRealUsed,
                'memRealFree' => $memRealFree,
                'memRealPercent' => $memRealPercent,
                'memPercent' => $memPercent,
                'memCachedPercent' => $memCachedPercent
            ]);
        }

        return $sysInfo;
    }

    /**
     * CPU 상세정보
     */
    private function getCpuInfo(): string
    {
        $stat1 = GetCoreInformation();
        sleep(1);
        $stat2 = GetCoreInformation();
        $data = GetCpuPercentages($stat1, $stat2);

        $ret = '';
        if(isset($data['cpu0']['user'])) {
            $ret .= $data['cpu0']['user'] . "%us,  ";
        }
        if(isset($data['cpu0']['sys'])) {
            $ret .= $data['cpu0']['sys'] . "%sy,  ";
        }
        if(isset($data['cpu0']['nice'])) {
            $ret .= $data['cpu0']['nice'] . "%ni, ";
        }
        if(isset($data['cpu0']['idle'])) {
            $ret .= $data['cpu0']['idle'] . "%id,  ";
        }
        if(isset($data['cpu0']['iowait'])) {
            $ret .= $data['cpu0']['iowait'] . "%wa,  ";
        }
        if(isset($data['cpu0']['irq'])) {
            $ret .= $data['cpu0']['irq'] . "%irq,  ";
        }
        if(isset($data['cpu0']['softirq'])) {
            $ret .= $data['cpu0']['softirq'] . "%softirq";
        }

        return $ret;
    }

    /**
     * 사용 메모리 정보
     */
    private function getMemoryInfo(): array
    {
        $dt = round(@disk_total_space(".") / (1024 * 1024 * 1024), 3);
        $df = round(@disk_free_space(".") / (1024 * 1024 * 1024), 3);
        $du = ($dt - $df); //е·Із”Ё
        $hdPercent = ((floatval($dt) != 0) ? round($du / $dt * 100, 2) : 0);

        return ['dt' => $dt, 'df' => $df, 'du' => $du, 'hdPercent' => $hdPercent];
    }

    /**
     * 네트워크 정보 조회
     */
    private function getNetworkInfo(): array
    {
        // 네트워크 정보 조회
        $networkResult = [];
        $networkData = @file("/proc/net/dev");

        if($networkData) {
            for ($i = 2; $i < count($networkData); $i++) {
                preg_match_all("/([^\s]+):[\s]{0,}(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/", $networkData[$i], $info);
                $networkResult[$i - 2] = [
                    'networkName' => $info[1][0],
                    'NetOutSpeed' => $info[10][0],
                    'NetInputSpeed' => $info[2][0],
                    'NetInput' => byteFormat($info[2][0]),
                    'NetOut' => byteFormat($info[10][0]),
                ];
            }
        }

        return $networkResult;
    }

    /**
     * PHP 정보
     * @method GET
     * @see /admin/config/server/php
     */
    public function php()
    {
        ob_start();
        phpinfo();
        $phpinfo = ob_get_contents();
        ob_end_clean();
        $phpinfo = preg_replace('%^.*<body>(.*)</body>.*$%ms', '$1', $phpinfo);
        ob_clean();

        return view('admin.config.php.index', [
            'subject' => 'PHP 정보',
            'phpinfo' => $phpinfo
        ]);
    }

    /**
     * DB 정보
     * @method GET
     * @see /admin/config/server/db
     */
    public function db()
    {
        return view('admin.config.db.index', [
            'subject' => 'DB 정보',
            'database' => config('database'),
            'drivers' => join(', ', \Illuminate\Support\Facades\DB::availableDrivers())
        ]);
    }
}
