<?php

class ACMS_POST_Logger_Download extends ACMS_POST_Logger_Info
{
    public function post()
    {
        try {
            $this->validateDownload();

            $limits = configArray('admin_limit_option');
            $limit = LIMIT ? LIMIT : $limits[config('admin_limit_default')];
            $limit = intval($limit);
            $levels = $this->Get->getArray('level');
            $suid = intval($this->Get->get('suid', 0));
            $repository = App::make('acms-logger-repository');
            assert($repository instanceof \Acms\Services\Logger\Repository);

            list($sql, $count) = $repository->getIndexSql($limit, PAGE, $levels, $suid, START, END);
            $q = $sql->get(dsn());
            $statement = DB::query($q, 'exec');

            $tempFile = 'audit_log_' . date('Y-m-d', REQUEST_TIME) . '.json';
            if (START && strpos(START, '1000-01-01') === false) {
                $tempFile = 'audit_log_' . date('Y-m-d', strtotime(START)) . '.json';
            }
            $path = MEDIA_STORAGE_DIR . $tempFile;
            $first = true;
            $fp = fopen($path, 'w');
            if ($fp === false) {
                throw new \RuntimeException('ファイルを開くことができませんでした: ' . $path);
            }
            fwrite($fp, "[\n");

            while ($log = DB::next($statement)) {
                if ($first) {
                    $first = false;
                } else {
                    fwrite($fp, ",\n");
                }
                $json = json_encode($this->buildData($log), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
                if ($json === false) {
                    throw new \RuntimeException('JSONエンコードに失敗しました: ' . json_last_error_msg());
                }
                fwrite($fp, $json);
            }
            fwrite($fp, "\n]");
            fclose($fp);

            $downloader = App::make('response.downloader');
            // handle() は @return never。assert で型を絞らないと「送出後に処理が続く」と解析される
            assert($downloader instanceof \Acms\Services\Response\FileDownloader);
            $downloader->handle($path, $tempFile, false, true);
        } catch (\Exception $e) {
            AcmsLogger::error($e->getMessage());
            return $this->Post;
        }
    }

    /**
     * @return void
     * @throws RuntimeException
     */
    protected function validateDownload(): void
    {
        // 監査ログはルートブログ限定の機能。BID を渡すと isControlBlog() が自ブログと配下を
        // 許すため子ブログ管理者が自分の BID で通過してしまうので、RBID を渡して
        // 「ルートブログの管理者か」を判定する。
        if (!sessionWithAdministration(RBID)) {
            throw new \RuntimeException('アクセス権限がありません');
        }
    }
}
