<?php

use Acms\Services\Facades\PublicStorage;
use Acms\Services\Facades\Logger;
use Acms\Services\Facades\Application as App;
use Acms\Services\Form\Repository;
use Acms\Services\Form\Authorization;

class ACMS_POST_Form extends ACMS_POST
{
    public $isCacheDelete  = false;

    /**
     * フォームリポジトリ（永続化）をコンテナから取得する
     *
     * @return \Acms\Services\Form\Repository
     */
    protected function formRepository(): Repository
    {
        return App::make('form.repository');
    }

    /**
     * フォームの認可判定をコンテナから取得する
     *
     * @return \Acms\Services\Form\Authorization
     */
    protected function formAuthorization(): Authorization
    {
        return App::make('form.authorization');
    }

    /**
     * 残った添付ファイルの削除
     * 送信まで行かず確認画面でフォームをキャンセルした場合に添付ファイルが残る為
     *
     * @param int $lifetime
     */
    public static function clearAttachedFile($lifetime = 1800)
    {
        $tempDirPath = ARCHIVES_DIR . config('mail_attachment_temp_dir', 'temp/');
        if (!PublicStorage::isDirectory($tempDirPath)) {
            return;
        }
        $fileList = PublicStorage::getFileList($tempDirPath);
        foreach ($fileList as $path) {
            if (!PublicStorage::isReadable($path)) {
                continue;
            }
            if (PublicStorage::isDirectory($path)) {
                continue;
            }
            $mtime = PublicStorage::lastModified($path);
            if (REQUEST_TIME - $lifetime > $mtime) {
                PublicStorage::remove($path);
                Logger::debug('添付ファイルの一時ファイルを削除しました', [
                    'path' => $path,
                ]);
                if (HOOK_ENABLE) {
                    $Hook = ACMS_Hook::singleton();
                    $Hook->call('mediaDelete', $path);
                }
            }
        }
    }

    /**
     * フォームのロード
     *
     * @param string $code
     * @return array{
     *  id: int,
     *  bid: int,
     *  code: string,
     *  name: string,
     *  scope: string,
     *  log: '1' | '0',
     *  data: \Field
     * }|false
     */
    public function loadForm($code)
    {
        return $this->formRepository()->findByCodeInTree($code, BID) ?? false;
    }

    /**
     * IDによるフォームの探索
     *
     * @param int $id
     * @return array{
     *  id: int,
     *  bid: int,
     *  code: string,
     *  name: string,
     *  scope: string,
     *  log: '1' | '0',
     *  data: \Field
     * }|null
     */
    public function findFormById(int $id): ?array
    {
        return $this->formRepository()->findById($id);
    }

    /**
     * フォームオプション（サーバーサイドのバリデーション）を組み込み
     *
     * @param Field $Option
     * @return array
     */
    function buildOptions($Option)
    {
        $dup = []; // メールアドレスの重複オプション

        $field = new Field_Validation();
        if ($takeover = $this->Post->get('field:takeover')) {
            $takeoverField = acmsUnserialize($takeover);
            if ($takeoverField instanceof Field) {
                $field->overload($takeoverField);
            }
            $this->Post->delete('field:takeover');
        }
        $field->overload($this->Post->dig('field'));

        foreach ($Option->getArray('field') as $i => $fd) {
            if (empty($fd)) {
                continue;
            }
            if (!($method = $Option->get('method', '', $i))) {
                continue;
            }
            $value  = $Option->get('value', '', $i);
            if ('converter' == $method) {
                $this->Post->set($fd . ':converter', $value);
            } elseif ('duplication' == $method) {
                $dup[] = $fd;
                $dup[] = $field->get($fd);
            } else {
                $field->setMethod($fd, $method, $value);
            }
        }
        $this->Post->addChild('field', $field);

        return $dup;
    }

    /**
     * フォームオプション（サーバーサイドのバリデーション）を組み込み
     *
     * @param Field $Field
     * @param string $fd
     * @return array|false
     */
    function getAttachedFilePath($Field, $fd)
    {
        if (
            1
            and preg_match('@^(.+)\@path$@', $fd, $match)
            and $Field->isExists($match[1])
            and $Field->isExists($match[1] . '@baseName')
        ) {
            $fd_file    = $match[1];
            $filename   = $Field->get($fd_file . '@baseName');
            $path       = $Field->get($fd_file . '@path');
            $original_name = $Field->get($fd_file . '@originalName');

            if ($download_name = $Field->get($fd_file . '@downloadName')) {
                $original_name = $download_name;
            }
            if (strlen($filename) === 0) {
                $filename = PublicStorage::mbBasename($path);
            }

            // Twigの場合はグローバル変数を使用せずに変数そのままで出力できるため、パスの存在チェックを行う
            $path = ltrim($path, '/');
            $realpath = PublicStorage::exists($path) ? $path : ARCHIVES_DIR . $path;
            $temppath = ARCHIVES_DIR . config('mail_attachment_temp_dir') . $filename;

            if (PublicStorage::exists($realpath) && PublicStorage::isFile($realpath)) {
                return [
                    'realpath'  => $realpath,
                    'temppath'  => $temppath,
                    'fieldpath' => config('mail_attachment_temp_dir') . $filename,
                    'fdname'    => $fd_file,
                    'original_name' => $original_name,
                ];
            }
        }

        return false;
    }

    /**
     * フォームIDの重複チェック
     *
     * @param string $code
     * @param int|null $formId
     * @param string $scope
     * @return boolean
     */
    function double($code, $formId = null, $scope = 'local')
    {
        if (empty($code)) {
            return true;
        }

        return !$this->formRepository()->existsCodeInTree($code, is_int($formId) ? $formId : null, $scope, BID);
    }

    /**
     * メールアドレスの重複チェック
     *
     * @param int $id
     * @param string $mail
     * @return boolean
     */
    function mailToDouble($id, $mail)
    {
        return !$this->formRepository()->existsMailInLog($id, $mail, BID);
    }
}
