<?php

namespace App\Utils;

use App\Models\SystemLog;
use App\Services\AccountService;
use App\Services\CacheService;
use App\Services\ModuleService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\View;

!(defined('IN_IA')) && define('IN_IA', 2);

class WeModule
{

    public $module;

    public $modulename;

    public $weid;

    public $uniacid;

    public $__define;

    /**
     * @throws \Exception
     */
    public function create($name){
        static $file;
        $classname = "\\Addons\\{$name}\\site";
        $file = public_path("/addons/{$name}/site.php");
        try {
            if (class_exists($classname)) {
                $Instance =   self::createModuleInstance($classname, $name);
            }else{
                if (!file_exists($file)) {
                    throw new \Exception('ModuleSite Definition File Not Found ' . $name, E_USER_WARNING);
                }
                require_once $file;
                $classname = "{$name}ModuleSite";
                if (!class_exists($classname)) {
                    trigger_error('ModuleSite Definition Class Not Found', E_USER_WARNING);
                    return null;
                }
                $Instance = self::createModuleInstance($classname, $name);
            }
        }catch (\Exception $e){
            SystemLog::systemRunning(
                '模块实例创建异常',
                'utils:WeModule',
                "创建模块实例时发生异常：{$e->getMessage()}",
                false,
                [
                    'exception_file' => $e->getFile(),
                    'exception_line' => $e->getLine(),
                    'exception_code' => $e->getCode(),
                    'exception_trace' => $e->getTrace(),
                    'module_name' => $name,
                    'classname' => $classname ?? null,
                ]
            );
            trigger_error($e->getMessage(), E_USER_WARNING);
            return null;
        }
        $Instance->__define = $file;
        return $Instance;
    }

    public static function createModuleInstance($classname, $module){
        global $_W;
        $o = new $classname();
        $o->uniacid = $o->weid = $_W['uniacid'];
        $o->modulename = $module;
        $o->module = ModuleService::fetch($module);
        self::defineConst($o);
        $o->inMobile = defined('IN_MOBILE');
        return $o;
    }

    public function doWebSystem_setting(){
        global $_W;
        if (checksubmit()){
            $moduleInfo = request()->input('module', []);
            if (!empty($moduleInfo)){
                AccountService::UpdateModules($this->uniacid, $this->modulename, array(
                    'name'=>trim($moduleInfo['name']),
                    'logo'=>trim($moduleInfo['logo'])
                ));
            }
            return redirect($this->createWebUrl());
        }
        $modules = AccountService::ExtraModules($this->uniacid);
        View::share('_W',$_W);
        return view('console.module.quickSetting', [
            'configs'=>$this->module['config'],
            'title'=>'应用配置',
            'moduleInfo'=>$modules[$this->modulename],
            'application_type'=>1
        ]);
    }

    public function pay($params){
        $payment = serv("payment");
        if (!$payment->enabled){
            if (!function_exists('\message')){
                require_once app_path('Helpers/app.php');
            }
            \message("支付服务暂不可用");
        }
        global $_W;
        $data = array(
            'tid'=>$params['tid'],
            'amount'=>$params['fee'],
            'subject'=>$params['title'],
            'openid'=>$_W['openid'],
            'isRecharge'=>(bool)$params['isRecharge']
        );
        return $payment->cashier($data, $this->modulename);
    }

    public function doWebMenu(){

    }

    private static function defineConst($obj) {
        global $_W;

        if (!defined('MODULE_ROOT')) {
            define('MODULE_ROOT', dirname($obj->__define));
        }
        if (!defined('MODULE_URL')) {
            define('MODULE_URL', $_W['siteroot'] . 'addons/' . $obj->modulename . '/');
        }
    }

    public function saveSettings($settings) {
        global $_W;
        $pars = array('module' => $this->modulename, 'uniacid' => $_W['uniacid']);
        $row = array();
        $row['settings'] = serialize($settings);
        $module = DB::table('uni_account_modules')->where(array('module'=>$this->modulename,'uniacid'=>$_W['uniacid']))->value('module');
        if ($module) {
            $result = pdo_update('uni_account_modules', $row, $pars);
        } else {
            $result = pdo_insert('uni_account_modules', array('settings' => serialize($settings), 'module' => $this->modulename, 'uniacid' => $_W['uniacid'], 'enabled' => 1));
        }
        CacheService::build_module($this->modulename, $_W['uniacid']);

        return $result;
    }

    protected function createMobileUrl($do, $query = array(), $noredirect = true, $addhost=false) {
        global $_W;
        $module_name = strtolower($this->modulename);
        $segment = "wem/{$module_name}".($do?'/'.$do:'');
        $url = (!empty($addhost) ? $_W['siteroot'] : '/') . $segment;
        if (empty($query)){
            $query = array();
        }
        $query['i'] = $_W['uniacid'];
        $queryString = http_build_query($query);
        $url .= '?' . $queryString;
        if (false === $noredirect) {
            $url .= '&wxref=mp.weixin.qq.com#wechat_redirect';
        }
        return $url;
    }

    protected function createWebUrl($do="", $query = array()) {
        $module_name = strtolower($this->modulename);
        return wurl("m/$module_name".($do?"/$do":''), $query);
    }

    /**
     * 获取模块视图
     * param array $data 视图渲染数据
     * param string $template 模板名称
     * return \Illuminate\Contracts\View\View
    */
    public function View($data, $template='index'){
        global $_W, $_GPC, $_MODULE_VIEW;
        $viewPath = public_path('addons/' . $this->modulename . '/views');
        try {
            View::addNamespace($this->modulename, $viewPath);
        }catch (\Exception $exception){
            SystemLog::systemRunning(
                '模块视图命名空间注册异常',
                'utils:WeModule',
                "注册模块视图命名空间时发生异常：{$exception->getMessage()}",
                false,
                [
                    'exception_file' => $exception->getFile(),
                    'exception_line' => $exception->getLine(),
                    'exception_code' => $exception->getCode(),
                    'exception_trace' => $exception->getTrace(),
                    'module_name' => $this->modulename,
                    'view_path' => $viewPath,
                ]
            );
            try {
                app('view')->addNamespace($this->modulename, $viewPath);
            } catch (\Exception $e2) {
                SystemLog::systemRunning(
                    '模块视图命名空间备用注册异常',
                    'utils:WeModule',
                    "备用方法注册模块视图命名空间时发生异常：{$e2->getMessage()}",
                    false,
                    [
                        'exception_file' => $e2->getFile(),
                        'exception_line' => $e2->getLine(),
                        'exception_code' => $e2->getCode(),
                        'exception_trace' => $e2->getTrace(),
                        'module_name' => $this->modulename,
                        'view_path' => $viewPath,
                    ]
                );
                // 记录错误
                error_log("Failed to register module view namespace: " . $e2->getMessage());
                session_exit($e2->getMessage());
            }
        }
        if (empty($data)){
            $data = array();
        }
        $_MODULE_VIEW = $this->modulename;
        $data['_W'] = $_W;
        $data['_GPC'] = $_GPC;
        View::share($data);
        return View::make($this->modulename . ":" .str_replace('/', '.', $template), $data);
    }

    public function template($filename, $extra='') {
        global $_W;
        $name = strtolower($this->modulename);
        $defineDir = dirname($this->__define);
        if (defined('IN_SYS')) {
            $source = IA_ROOT . "/web/themes/{$_W['template']}/$name/$extra$filename.html";
            $compile = storage_path("framework/tpls/web/$name/$extra$filename.tpl.php");
            if (!is_file($source)) {
                $source = IA_ROOT . "/web/themes/default/$name/$filename.html";
            }
            if (!is_file($source)) {
                $source = $defineDir . "/{$extra}template/$filename.html";
            }
            if (!is_file($source) && !empty($extra)) {
                $source = $defineDir . "/template/$filename.html";
            }
            if (!is_file($source)) {
                $source = IA_ROOT . "/web/themes/{$_W['template']}/$filename.html";
            }
            if (!is_file($source)) {
                $source = IA_ROOT . "/web/themes/default/$filename.html";
            }
        } else {
            $source = $defineDir . "/{$extra}template/mobile/$filename.html";
            $compile = storage_path("framework/tpls/app/$name/$extra$filename.tpl.php");
            if (!is_file($source)) {
                $source = $defineDir . "/{$extra}template/mobile/touch/$filename.html";
            }
            if (!is_file($source)) {
                $source = $defineDir . "/{$extra}template/webapp/$filename.html";
            }
        }

        if (!is_file($source)) {
            session()->save();
            exit("Error: template source '$filename' is not exist!");
        }
        $paths = pathinfo($compile);
        $compile = str_replace($paths['filename'], $_W['uniacid'] . '_' . $paths['filename'], $compile);
        if (!function_exists("tpl_compile")){
            include_once app_path("Helpers/smarty.php");
        }
        if (DEVELOPMENT || !is_file($compile) || filemtime($source) > filemtime($compile)) {
            tpl_compile($source, $compile, $this->modulename);
        }

        return $compile;
    }

    protected function getFunctionFile($name) {
        $module_type = 0 === stripos($name, 'doWeb') ? 'web' : 'mobile';
        $function_name = 'web' == $module_type ? strtolower(substr($name, 5)) : strtolower(substr($name, 8));
        $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/' . $module_type;
        return "$dir/{$function_name}.inc.php";
    }

    /**
     * @throws \Exception
     */
    public function __call($name, $param) {
        $file = $this->getFunctionFile($name);
        if (file_exists($file)) {
            require $file;
            session_exit();
        }
        abort(404, "模块方法{$name}不存在");
    }

}
