<?php

namespace pictpostpersonal\service;

use PDO;
use pictpostpersonal\model\Setting;
use pictpostpersonal\model\ThemeSetting;
use pictpostpersonal\NoSixTemplate2;

use const pictpostpersonal\THEMES_PATH;

class ThemeService
{
    const THEME_SETTING_CSV_TYPE = 0;
    const THEME_SETTING_CSV_NAME = 1;
    const THEME_SETTING_CSV_DEFAULT = 4;

    protected PDO $db;
    protected Setting $setting;
    protected static string $cache_dir;

    public function __construct($db, $setting, $cache_dir = './env/template_cache')
    {
        $this->db = $db;
        $this->setting = $setting;
        self::$cache_dir = $cache_dir;
    }

    /**
     * テーマ情報を適用したテンプレートエンジンを取得する
     *
     * @return NoSixTemplate2
     * 
     */
    public static function getThemeTemplate(string $template_name, PDO $db, Setting $setting, string $theme_cache = ""): NoSixTemplate2
    {
        if ($theme_cache == "") {
            $theme_cache = self::$cache_dir;
        }
        $theme = $setting->getValue('theme', '');
        $template = new NoSixTemplate2($template_name, ['./env/templates', './themes/' . $theme, './core/templates', './core/templates_sys'], $theme_cache);
        $theme_model = new ThemeSetting($db);
        $theme_data = $theme_model->loadThemeSettings($theme);
        $template->set_data('theme_item', $theme_data);

        return $template;
    }

    /**
     * テンプレート固有設定の取得
     *
     * @param array $theme_info     テーマ定義
     * @param array $theme_setting  テーマ設定
     * 
     * @return array
     * 
     */
    public function getThemeValues(array $theme_info, array $theme_setting): array
    {
        $set_array = [];
        foreach ($theme_info['setting'] ?? [] as $item) {
            $set_array[$item[self::THEME_SETTING_CSV_NAME]]['type'] = $item[self::THEME_SETTING_CSV_TYPE];
            if ($item[self::THEME_SETTING_CSV_TYPE] === 'file') {
                //ファイルについてはURL展開
                $set_array[$item[self::THEME_SETTING_CSV_NAME]]['value'] = BASE_URL . '/themes/' . $item[self::THEME_SETTING_CSV_NAME];
            } else {
                $set_array[$item[self::THEME_SETTING_CSV_NAME]]['value'] = $theme_setting[$item[self::THEME_SETTING_CSV_NAME]]['value'] ?? $item[self::THEME_SETTING_CSV_DEFAULT];
            }
        }

        //初期化データを取得
        $set_array['theme_init']['value'] = $theme_setting[$theme_info['theme']]['theme_init']['value'] ?? '';

        return $set_array;
    }

    /**
     * テーマ一覧を取得する
     *
     * @return array
     * 
     */
    public function getThemes(): array
    {
        $themes_info = [];
        foreach (scandir(THEMES_PATH) as $item) {
            if ($item === '.' || $item === '..') continue;
            $path = THEMES_PATH . DIRECTORY_SEPARATOR . $item;
            if (is_dir($path)) {
                $theme = $this->getTheme($path);
                if ($theme == null) {
                    //infoが不正
                    continue;
                }
                $themes_info[] = $theme;
            }
        }
        return $themes_info;
    }

    /**
     * 指定されたディレクトリ内にある、テーマの設定ファイルを取得する
     *
     * @param string $theme_path テーマのディレクトリ名。　
     * 
     * @return array テーマ情報の配列。["name"=>"", "info" => [],"setting" => []]
     * 
     */
    public function getTheme(string $theme_dir): ?array
    {
        $last_dir = basename(rtrim($theme_dir, '/'));
        $filepath = $theme_dir . DIRECTORY_SEPARATOR . 'info.txt';
        if (!file_exists($filepath)) {
            return null;
        }
        $info = $this->parseThemeInfo($filepath);
        if (!isset($info['title'])  || !isset($info['author'])) {
            return null;
        }

        if (!isset($info['memo'])) {
            $info['memo'] = '';
        }
        if (!isset($info['vesion'])) {
            $info['version'] = '';
        }
        if (!isset($info['url'])) {
            $info['url'] = '';
        }
        if (!isset($info['licence'])) {
            $info['licence'] = '';
        }

        $info['theme'] = $last_dir;
        return $info;
    }

    /**
     * info.txt内の拡張記述による設定項目定義を読み取る
     *
     * @param string $filepath
     * 
     * @return array
     * 
     */
    private function parseThemeInfo(string $filepath): array
    {
        $key_value_pairs = [];
        $csv_data = [];

        $lines = file($filepath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $is_csvsection = false;

        foreach ($lines as $line) {
            if ($line === '---SETTING---') {
                $is_csvsection = true;
                continue;
            }

            if ($is_csvsection) {
                $csv_data[] = str_getcsv($line);
                foreach ($csv_data[0] as $index => $value) {
                    $csv_data[0][$index] = htmlspecialchars($value);
                }
            } else {
                [$key, $value] = explode(':', $line, 2);
                $key_value_pairs[trim($key)] = str_replace('\n', '<br>', htmlspecialchars(trim($value)));
            }
        }
        $key_value_pairs['setting'] = $csv_data;
        return $key_value_pairs;
    }

    private function checkTemplatesCode($theme_dir)
    {
        $path = THEMES_PATH . DIRECTORY_SEPARATOR . $theme_dir;
        $files = glob($path . '/*.php');
        $result = false;
        foreach ($files as $file) {
            $content = file_get_contents($file);

            // PHP開始タグが存在しない場合は即 false
            if (!preg_match('/<\?(php|=)?/i', $content)) {
                continue;
            }

            // PHPコードとしてトークン解析
            $tokens = @token_get_all($content);

            foreach ($tokens as $token) {
                if (is_array($token)) {
                    // PHPタグを検出
                    if (in_array($token[0], [T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO], true)) {
                        $result =  true;
                        break;
                    }
                }
            }
        }
        return $result;
    }

    public function getUserResourceFilePath($file): string
    {
        $base_dir = realpath('./user_resource/themes_resource/');
        $theme = $this->setting->getValue('theme', 'default');
        $file_path = realpath("./user_resource/themes_resource/$theme/$file");
        if ($file_path === false || strpos($file_path, $base_dir) !== 0) {
            return '';
        }
        return $file_path;
    }

    public function createSettingFields(string $current_theme, array $theme_info, array $theme_setting): string
    {
        if ($current_theme === $theme_info['theme']) {
            $html = "<div id=\"theme_setting_{$theme_info['theme']}\" class=\"theme_section active\">";
        } else {
            $html = "<div id=\"theme_setting_{$theme_info['theme']}\" class=\"theme_section\">";
        }
        $html .= "<div class=\"theme_info\">";
        $html .= "<div class=\"\">{$theme_info['memo']}</div>";
        $html .= "<div class=\"\"><a href=\"{$theme_info['url']}\" target=\"_blank\">{$theme_info['url']}</a></div>";
        $html .= "<div class=\"\">{$theme_info['version']}</div>";
        if ($theme_info['licence']) {
            $html .= "<div class=\"\">Licnence: {$theme_info['licence']}</div>";
        }

        //初期化済みかチェックし、未初期化ならPHPコードが含まれているかチェック、警告
        $init = $this->getSettingValue('theme_init', '', $theme_setting);
        if ($init == '') {
            $use_code = $this->checkTemplatesCode($theme_info['theme']);
            if ($use_code) {
                $html .= "<div class=\"\" style=\"font-size:0.8rem;color:#ff5555\">※このテーマではPHPスクリプトが使用されています。安全な配布元から入手した場合のみ使用してください。</div>";
                $html .= "<input type=\"hidden\" class=\"form-control\" name=\"theme_setting_{$theme_info['theme']}:theme_init\" value=\"in_code\">";
            } else {
                $html .= "<input type=\"hidden\" class=\"form-control\" name=\"theme_setting_{$theme_info['theme']}:theme_init\" value=\"safe\">";
            }
        } else if ($init == 'in_code') {
            $html .= "<div class=\"\" style=\"font-size:0.8rem;color:#ff5555\">※このテーマではPHPスクリプトが使用されています。安全な配布元から入手した場合のみ使用してください。</div>";
        }
        $html .= "</div>";




        foreach ($theme_info['setting'] ?? [] as $item) {
            switch (strtolower($item[0])) {
                case 'text':
                    $html .= $this->createTextField($theme_info['theme'], $item, $this->getSettingValue($item[1], $item[4], $theme_setting));
                    break;
                case 'textarea':
                    $html .= $this->createTextAreaField($theme_info['theme'], $item, $this->getSettingValue($item[1], $item[4], $theme_setting));
                    break;
                case 'color':
                    $html .= $this->createColorField($theme_info['theme'], $item, $this->getSettingValue($item[1], $item[4], $theme_setting));
                    break;
                case 'check':
                    $html .= $this->createCheckField($theme_info['theme'], $item, $this->getSettingValue($item[1], $item[4], $theme_setting));
                    break;
                case 'file':
                    $file_exists = file_exists($this->getUserResourceFilePath($item[3]));
                    $html .= $this->createFileField($theme_info['theme'], $item, $file_exists);
                    break;
            }
        }
        $html .= '</div>';
        return $html;
    }

    private function getSettingValue($key, $defult, $theme_setting): string
    {
        if (isset($theme_setting[$key])) {
            return $theme_setting[$key]['value'];
        } else {
            return $defult;
        }
    }

    private function createInfoText($info)
    {
        if ($info == '') {
            return '';
        }
        $info = htmlspecialchars($info);
        return "<div class=\"form_info\">$info</div>";
    }

    private function createTextField(string $theme_name, array $item, string $value): string
    {
        $value = htmlspecialchars($value);
        $item[1] = htmlspecialchars($item[1]);
        $item[2] = htmlspecialchars($item[2]);

        $info = $this->createInfoText($item[3]);
        $html = "<input type=\"hidden\" name=\"theme_setting_type:$theme_name:{$item[1]}\" value=\"text\">";
        $html .= "<div class=\"form-group\"><label for=\"theme_setting_{$theme_name}:{$item[1]}\" class=\"form-label\">{$item[2]}</label>";
        $html .= "<input type=\"text\" class=\"form-control\" name=\"theme_setting_{$theme_name}:{$item[1]}\" id=\"theme_setting_{$theme_name}:{$item[1]}\" value=\"$value\"><div class=\"form-text\">$info</div></div>";
        return $html;
    }
    private function createTextAreaField(string $theme_name, array $item, string $value): string
    {
        $value = htmlspecialchars($value);
        $item[1] = htmlspecialchars($item[1]);
        $item[2] = htmlspecialchars($item[2]);
        $item[3] = htmlspecialchars($item[3]);

        $info = $this->createInfoText($item[3]);
        $html = "<input type=\"hidden\" name=\"theme_setting_type:$theme_name:{$item[1]}\" value=\"textarea\">";
        $html .= "<div class=\"form-group\"><label for=\"theme_setting_{$theme_name}:{$item[1]}\" class=\"form-label\">{$item[2]}</label>";
        $html .= "<textarea class=\"form-control\" name=\"theme_setting_{$theme_name}:{$item[1]}\" id=\"theme_setting_{$theme_name}:{$item[1]}\">$value</textarea><div class=\"form-text\">$info</div></div>";
        return $html;
    }
    private function createColorField(string $theme_name, array $item, string $value): string
    {
        $value = htmlspecialchars($value);
        $item[1] = htmlspecialchars($item[1]);
        $item[2] = htmlspecialchars($item[2]);
        $item[3] = htmlspecialchars($item[3]);

        $info = $this->createInfoText($item[3]);
        $html = "<input type=\"hidden\" name=\"theme_setting_type:$theme_name:{$item[1]}\" value=\"color\">";
        $html .= "<div class=\"form-group\"><label for=\"theme_setting_{$theme_name}:{$item[1]}\" class=\"form-label\">{$item[2]}</label>";
        $html .= "<input class=\"form-control\" type=\"color\" name=\"theme_setting_{$theme_name}:{$item[1]}\" id=\"theme_setting_{$theme_name}:{$item[1]}\" value=\"$value\"><div class=\"form-text\">$info</div></div>";
        return $html;
    }
    private function createCheckField(string $theme_name, array $item, string $value): string
    {
        $value = htmlspecialchars($value);
        $item[1] = htmlspecialchars($item[1]);
        $item[2] = htmlspecialchars($item[2]);
        $item[3] = htmlspecialchars($item[3]);

        $info = $this->createInfoText($item[3]);
        $check = '';
        if ($value) {
            $check = 'checked';
        }
        $html = "<input type=\"hidden\" name=\"theme_setting_type:$theme_name:{$item[1]}\" value=\"check\"><input class=\"hide\" type=\"hidden\" name=\"theme_setting_{$theme_name}:{$item[1]}\" value=\"0\">";
        $html .= "<div class=\"form-group\">";
        $html .= "<input class=\"flat_input\" type=\"checkbox\" name=\"theme_setting_{$theme_name}:{$item[1]}\" id=\"theme_setting_{$theme_name}:{$item[1]}\"  $check> ";
        $html .= "<label for=\"theme_setting_{$theme_name}:$item[1]\">{$item[2]}</label><div class=\"form-text\">$info</div></div>";
        return $html;
    }
    private function createFileField(string $theme_name, array $item, string $value): string
    {
        $value = htmlspecialchars($value);
        $item[1] = htmlspecialchars($item[1]);
        $item[2] = htmlspecialchars($item[2]);
        $item[3] = htmlspecialchars($item[3]);
        $item[4] = htmlspecialchars($item[4]);

        $info = $this->createInfoText($item[3]);
        $html = "<input type=\"checkbox\" class=\"hide\" name=\"use::theme_setting_{$theme_name}:{$item[1]}\" id=\"use_theme_setting_{$theme_name}:{$item[1]}\" checked>";
        $html .= "<input type=\"hidden\" name=\"theme_setting_type:$theme_name:{$item[1]}\" value=\"file\">";
        $html .= "<div class=\"form-group\"><label for=\"theme_setting_{$theme_name}:{$item[1]}\" class=\"form-label\">{$item[2]}</label>";
        $html .= "<input type=\"file\" class=\"hide\" name=\"theme_setting_{$theme_name}:{$item[1]}\" id=\"theme_setting_{$theme_name}:{$item[1]}_file\">";
        if (file_exists($this->getUserResourceFilePath($item[4]))) {
            $html .= "<span class=\"file_status\" data-target=\"theme_setting_{$theme_name}:{$item[1]}_file\"><a href=\"" . BASE_URL . '/user_resource/themes_resource/' . $theme_name . '/' . $item[4] . "\" target=\"_blank\">[指定あり]</a></span> ";
        } else {
            $html .= "<span class=\"file_status\" data-target=\"theme_setting_{$theme_name}:{$item[1]}_file\">[指定なし]</span> ";
        }
        $html .= "<button class=\"file_button btn btn-primary btn-sm\" data-target=\"theme_setting_{$theme_name}:{$item[1]}_file\">変更</button> ";
        $html .= "<button class=\"file_clear_button btn btn-sm btn-secondary\" data-target=\"theme_setting_{$theme_name}:{$item[1]}\">クリア</button>";
        $html .= "<div class=\"form-text\">$info</div></div>";

        return $html;
    }
}
