<?php

namespace pictpostpersonal\controller\page;

use pictpostpersonal\controller\ControllerBase;

use Exception;
use pictpostpersonal\Environment;
use pictpostpersonal\FlashMessage;
use pictpostpersonal\Request;
use pictpostpersonal\Result;
use pictpostpersonal\model\Account;
use pictpostpersonal\model\Article;
use pictpostpersonal\model\ThemeSetting;
use pictpostpersonal\NoSixTemplate2;
use pictpostpersonal\service\ThemeService;


class SettingPage extends ControllerBase
{

    /**
     * 設定画面を表示する
     *
     * @return Router用リザルト
     * 
     */
    public function show(Request $request): Result
    {
        if (!$this->auth->isLogin()) {
            //ログインしていない場合はリダイレクト
            FlashMessage::setMessage('login', ['message' => '', 'url' => '/setting']);
            Result::redirect('/login');
        }

        //設定値を表示用にフォーマットする
        $show_settings =  array_merge(array(), $this->setting->load());
        if (!$show_settings) {
            $this->setting->initialize_values();
            $show_settings = array_merge(array(), $this->setting->fields);
        }
        $show_settings['version'] = Environment::getVersion();
        $show_settings['url_system_root'] = Environment::getSystemUrl();

        //アカウント一覧
        $accounts = new Account($this->db);
        $account_data = $accounts->findAll();
        $cnt = count($account_data);
        //5件に満たない場合は空行を追加
        for ($i = 0; $i < 5 - $cnt; $i++) {
            $account_data[] = ['id' => '', 'url' => '', 'icon' => ''];
        }

        foreach ($this->setting->field_info as $index => [$field_name, $default_value, $type]) {
            if ($type == '1') {
                //BOOL項目を表示用にフォーマットする
                $show_settings[$field_name] = $show_settings[$field_name]  ? 'checked' : '';
            } else {
                //表示用にHTMLをエスケープ
                $show_settings[$field_name] = h($show_settings[$field_name] ?? '');
            }
        }

        //インデックスページ他
        $article_model = new Article($this->db, $this->setting);
        $article = $article_model->getIndexPage();
        $show_settings['index_text'] = htmlspecialchars($article['contents'] ?? '');
        $article = $article_model->getEntryPage();
        $show_settings['entry_text'] = htmlspecialchars($article['contents'] ?? '');
        $article = $article_model->getNSFWPage();
        $show_settings['nsfw_text'] = htmlspecialchars($article['contents'] ?? '');


        //テーマ関連
        $themes_service = new ThemeService($this->db, $this->setting);

        //テーマ情報
        $theme_model = new ThemeSetting($this->db);
        $theme_settings = $theme_model->loadAllThemeSettings();

        //テーマ一覧
        $themes = $themes_service->getThemes();
        $themes_setting_html = '';
        foreach ($themes as $theme_info) {
            $theme_values = $themes_service->getThemeValues($theme_info, $theme_settings);
            $themes_setting_html .= $themes_service->createSettingFields($show_settings['theme'], $theme_info, $theme_values);
        }

        //ユーザーCSS読み込み
        $user_css_path =  './user_resource/user.css';
        if (file_exists($user_css_path)) {
            $show_settings['user_css'] = htmlspecialchars(file_get_contents($user_css_path));
        } else {
            $show_settings['user_css'] = '';
        }

        //UIレンダリング
        if($request->getArgs('mode', '') == 'initialize')
        {
            $template = new NoSixTemplate2('template2_initialize_setting.php', ['./env/templates', './env/themes/' . $this->setting->getValue('theme', ''), './core/templates', './core/templates_sys'], './env/template_cache');
        }
        else{
            $template = new NoSixTemplate2('template2_setting.php', ['./env/templates', './env/themes/' . $this->setting->getValue('theme', ''), './core/templates', './core/templates_sys'], './env/template_cache');
        }
        self::setSiteData($template); //サイト関連情報を設定
        self::setSystemArea($template); //管理系情報を設定
        $template->set_data('settings', $show_settings, true);
        $template->set_data('accounts', $account_data);
        $template->set_data('version', $show_settings['version']);
        $template->set_data('themes', $themes);
        $template->set_data('theme_settings', $theme_settings);
        $template->set_data('themes_setting_html', $themes_setting_html);
        //$template->set_data('VERSION', $VERSION);
        ob_start();
        $template->display();
        $output = ob_get_clean();

        $result = new Result();
        $result->output = $output;
        return $result;
    }


    /**
     * テーマ一覧を生成する
     *
     * @param string $directory  テーマのルートディレクトリ
     * 
     * @return array ["theme", "title","authoer"]
     * 
     */
    function listThemes(string $directory): array
    {
        if (!is_dir($directory)) {
            return [];
        }
        $contents = scandir($directory);
        $subdirectories = [];
        foreach ($contents as $item) {
            if ($item !== '.' && $item !== '..' && is_dir($directory . DIRECTORY_SEPARATOR . $item)) {
                if (file_exists("$directory/$item/info.txt")) {
                    $info = $this->parseThemeInfo($item, "$directory/$item/info.txt");
                } else {
                    $info = ['theme' => $item, 'title' => $item, 'author' => '', 'url' => '', 'memo' => '', 'license' => ''];
                }
                $subdirectories[] = $info;
            }
        }
        return $subdirectories;
    }

    /**
     * テーマ情報ファイルを読み込む
     *
     * @param string $theme
     * @param string $filePath
     * 
     * @return array
     * 
     */
    function parseThemeInfo(string $theme, string $file_path): array
    {
        $data = ['theme' => "$theme", 'title' => "$theme", 'author' => '', 'url' => '', 'memo' => '', 'license' => ''];
        $current_title = null;
        $current_value = '';

        if (!file_exists($file_path)) {
            throw new Exception("File not found: $file_path");
        }

        $file = fopen($file_path, 'r');
        if (!$file) {
            throw new Exception("Unable to open file: $file_path");
        }

        $is_csvsection = false;
        while (($line = fgets($file)) !== false) {
            $line = rtrim($line, "\r\n");
            $line = str_replace('\:', '&#58;', $line);

            if ($line === '---SETTING---') {
                $is_csvsection = true;
                continue;
            }
            if ($is_csvsection) {
                $csv_data[] = str_getcsv($line);
            } else {
                if (preg_match('/^([^:]+):(.+)$/', $line, $matches)) {
                    if ($current_title !== null) {
                        $data[$current_title] = $current_value;
                    }
                    $current_title = $matches[1];
                    $current_value = $matches[2];
                } else {
                    $current_value .= ($current_value === '' ? '' : "\n") . $line;
                }
            }
        }
        if ($current_title !== null) {
            $data[$current_title] = str_replace("\n", '<br>', htmlspecialchars(strip_tags($current_value ?? '')));
        }

        fclose($file);

        return $data;
    }
    /**
     * 設定を保存する
     *
     * @param Request $request
     * 
     * @return Router用リザルト。内容はJSON。
     * 
     */
    public function save(Request $request): Result
    {
        if (Environment::isDemoMode()) {
            //ログインしていない場合はエラー

            return new Result(200, "{\"status\":\"error\", \"message\":\"デモモードでは設定は変更できません\"}");
        }
        if (!$this->auth->isLogin()) {
            //ログインしていない場合はエラー
            return new Result(400, "{\"status\":\"error\", \"message\":\"ログインしていません\"}");
        }

        try {
            // テーマ変更検知用に現在のテーマを保存
            $old_theme = $this->setting->getValue('theme', '');

            $this->db->beginTransaction();

            //POSTされた値を設定
            foreach ($this->setting->field_info as $index => $field) {
                //$field[0]:項目名
                //$field[1]:デフォルト値

                if ($request->hasArgs($field[0])) {
                    if ($field[0] == 'user_css') {
                        //WAF対策のデコード
                        $this->setting->SetValue($field[0], base64_decode($request->getArgs($field[0], $field[1])));
                    } else {
                        $this->setting->SetValue($field[0], $request->getArgs($field[0], $field[1]));
                    }
                }
            }

            //画像ファイル類
            $dest_path = $this->fileCopy($request, 'ogimage_file', './images/ogimage.<ext>');
            if ($dest_path != '') {
                $this->setting->SetValue('use_ogimage', true);
                $this->setting->SetValue('ogimage', basename($dest_path));
            }
            $dest_path = $this->fileCopy($request, 'banner_file', './images/banner.<ext>');
            if ($dest_path) {
                $this->setting->SetValue('use_banner', true);
                $this->setting->SetValue('banner', basename($dest_path));
            }
            $dest_path = $this->fileCopy($request, 'icon_file', './images/usericon.<ext>');
            if ($dest_path) {
                $this->setting->SetValue('use_icon', true);
                $this->setting->SetValue('icon', basename($dest_path));
            }
            $dest_path = $this->fileCopy($request, 'favicon_file', './images/favicon.<ext>');
            if ($dest_path) {
                $this->setting->SetValue('use_favicon', true);
                $this->setting->SetValue('favicon', basename($dest_path));
            }
            $dest_path = $this->fileCopy($request, 'mini_banner_file', './images/mini_banner.<ext>');
            if ($dest_path) {
                $this->setting->SetValue('use_mini_banner', true);
                $this->setting->SetValue('mini_banner', basename($dest_path));
            }
            $this->setting->save(false); //設定保存

            //THEME設定値を保存
            $themes_service = new ThemeService($this->db, $this->setting);
            $themes_info = $themes_service->getThemes();
            $theme_model = new ThemeSetting($this->db);
            $theme_settings = $theme_model->loadAllThemeSettings();
            foreach ($themes_info as $index => $theme_info) {
                $theme = $theme_info['theme'];
                foreach ($theme_info["setting"] as $item) {
                    if ($item[0] == "file") {
                        $dest_path = $this->fileCopy($request, "theme_setting_{$theme}:$item[1]", "./user_resource/themes_resource/{$theme}/$item[4]");
                        $file_remove = $request->getArgs("use::theme_setting_$theme:$item[1]", false);
                        if ($dest_path == "" && !$file_remove) {
                            //新ファイルの指定がなく、かつ削除指定がある場合はファイルを消去する（新ファイルの指定がある場合は上書き済み）
                            if (file_exists("./user_resource/themes_resource/{$theme}/$item[4]")) {
                                unlink("./user_resource/themes_resource/{$theme}/$item[4]");
                            }
                        }

                        if (file_exists("./user_resource/themes_resource/{$theme}/$item[4]")) {
                            $theme_settings[$theme][$item[1]]['value'] = "/user_resource/themes_resource/{$theme}/$item[4]";
                        } else {
                            $theme_settings[$theme][$item[1]]['value']  = "/themes/{$theme}/defult_files/$item[4]";
                        }
                        $theme_settings[$theme][$item[1]]['type'] = 'file';
                    } else {
                        $theme_settings[$theme][$item[1]]['value'] = $request->getArgs("theme_setting_$theme:$item[1]", $item[4]);
                        $theme_settings[$theme][$item[1]]['type'] = $item[0];
                    }
                }
                $theme_settings[$theme]['theme_init']['value'] = $request->getArgs("theme_setting_$theme:theme_init", '');
                $theme_settings[$theme]['theme_init']['type'] = 'text';
            }
            $theme_model->saveAllThemeSettings($theme_settings, false); //テーマ設定保存



            //アカウントリンク保存
            $sns_accounts = [];
            if (isset($request->args_raw['sns_url'])) {
                foreach ($request->args_raw['sns_url'] as $index => $snsurl) {
                    $sns_accounts[] = [
                        'url' => $request->args_raw['sns_url'][$index] ?? '',
                        'icon' => $request->args_raw['sns_icon'][$index] ?? '',
                        'type' => strpos($request->args_raw['sns_icon'][$index], 'fa-') === false ? '1' : '0'
                    ];
                }
            }

            //アカウントリンク用アイコンアップロード
            if (isset($_FILES['sns_icon_upload'])) {
                for ($i = 0; $i < count($_FILES['sns_icon_upload']['tmp_name']); $i++) {
                    if (is_uploaded_file($_FILES['sns_icon_upload']['tmp_name'][$i])) {
                        $copy = "./images/sns$i.<ext>";
                        $dest_path = $this->fileCopy($request, 'sns_icon_upload', $copy, $i);
                        $sns_accounts[$i]['icon'] =  basename($dest_path);
                        $sns_accounts[$i]['type'] =  '1';
                    }
                }
            }

            $account = new Account($this->db);
            $account->clear();
            if (isset($request->args_raw['sns_url'])) {
                foreach ($sns_accounts as $index => $sns) {
                    if (isset($sns) && trim($sns['url']) != '') {
                        $account->create($sns['url'], $sns['icon'], $sns['type']);
                    }
                }
            }

            //トップページ
            $article = new Article($this->db, $this->setting);
            $article_data = $article->getIndexPage();
            $article_data['contents'] =  base64_decode($request->args_raw['index_text'] ?? '');
            if (isset($article_data['id'])) {
                $article->update($article_data, [], false);
            } else {
                $article->create($article_data, [], false);
            }

            $article_data = $article->getEntryPage();
            $article_data['contents'] =  base64_decode($request->args_raw['entry_text'] ?? '');
            if (isset($article_data['id'])) {
                $article->update($article_data, [], false);
            } else {
                $article->create($article_data, [], false);
            }

            $article_data = $article->getNSFWPage();
            $article_data['contents'] =  base64_decode($request->args_raw['nsfw_text'] ?? '');
            if (isset($article_data['id'])) {
                $article->update($article_data, [], false);
            } else {
                $article->create($article_data, [], false);
            }

            // ユーザーCSSの保存
            if (isset($request->args_raw['user_css'])) {
                $user_css_dir = './user_resource';
                $user_css_path = $user_css_dir . '/user.css';

                // user_resourceディレクトリが存在しない場合は作成
                if (!file_exists($user_css_dir)) {
                    mkdir($user_css_dir, 0755, true);
                }

                // user.cssに書き込み
                file_put_contents($user_css_path,  base64_decode($request->args_raw['user_css']));
            }

            $this->db->commit();

            // テーマが変更された場合、テンプレートキャッシュを削除
            $new_theme = $this->setting->getValue('theme', '');
            if ($old_theme !== $new_theme) {
                $this->clearTemplateCache();
            }

            $result = new Result();
            $result->mime_type = 'application/json';
            $result->output = "{\"status\":\"success\"}";
            return $result;
        } catch (Exception $ex) {
            $this->db->rollBack();
            $this->log->log('SettingSaveError,' . $ex->getMessage());
            $result = new Result();
            $result->mime_type = 'application/json';
            $result->output = "{\"status\":\"error\"}";
            return $result;
        }
    }

    function fileCopy(Request $req, string $file_name, string $dest, $index = 0): string
    {
        $file = $req->getFile($file_name, $index);
        if ($file === null) {
            return '';
        }

        if (!file_exists(dirname($dest))) {
            mkdir(dirname($dest));
        }

        if (!$file->checkAllowedExtension(['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
            die('許可されていないファイル形式がアップロードされました');
        }
        if ($file->getError() != 0) {
            die('アップロードに失敗しました');
        }
        $extension = $file->getExtension();
        $dest_file_path = str_replace('<ext>', $extension, $dest);
        copy($file->tmp_name, $dest_file_path);
        return $dest_file_path;
    }

    /**
     * テンプレートキャッシュを削除する
     *
     * @return void
     *
     */
    private function clearTemplateCache(): void
    {
        $cache_dir = './env/template_cache';
        if (is_dir($cache_dir)) {
            $cache_files = glob($cache_dir . '/*.cache');
            if ($cache_files !== false) {
                foreach ($cache_files as $cache_file) {
                    unlink($cache_file);
                }
            }
        }
    }
}
