<?php

use Phalcon\Mvc\Model\Transaction\Failed as TxFailed;
use Carbon\Carbon;

class DiskusiService
{
    private $config;
    private $shared;
    private $request;
    private $minio;

    const BANSOS_NOTIFICATION_CONFIRMATION = 0;
    const BANSOS_NOTIFICATION_FOLLOWUP = 1;
    const BANSOS_NOTIFICATION_COMMENT = 2;
    const BANSOS_NOTIFICATION_CREATE = 3;

    public function __construct($config, $shared, $request, $minio = null)
    {
        $this->config = $config;
        $this->shared = $shared;
        $this->request = $request;
        $this->minio = $minio;
    }

    private function createNewTag($label) {
        $tag = new Tags();
        $tag->label = $label;
        $tag->create();
        return $tag->id;
    }

    public function create($validatedRequest, $type, $overrideQuota = 3)
    {
        if ($this->containBlacklist($validatedRequest['judul']) || $this->containBlacklist($validatedRequest['konten_diskusi'])) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Judul/Konten diskusi mengandung kata yang tidak diperbolehkan');
        }

        $validatedRequest["link_terkait"] = array_key_exists("link_terkait", $validatedRequest) ? $validatedRequest["link_terkait"] : '';

        $produkResult = Produk::findByIdIndex($validatedRequest['produk_id']);

        if (count($produkResult) < 1) {
            throw new ValidationException([
                [
                    'field' => 'produk_id',
                    'message' => 'Produk tidak ditemukan'
                ]
            ]);
        }

        $produk = $produkResult[0];

        $kategoriDiskusi = KategoriDiskusi::findFirst(
            [
                "produk_id = :produk_id:",
                "bind" => [
                    "produk_id" => $validatedRequest['produk_id']
                ]
            ]
        );

        if (empty($kategoriDiskusi)) {
            throw new ValidationException([
                [
                    'field' => 'produk_id',
                    'message' => 'Kategori diskusi dengan produk(' . $validatedRequest['produk_id'] . ') tidak ditemukan.'
                ]
            ]);
        }

        $this->checkUserCreateDiscussionQuota($this->shared->user->um_id, $overrideQuota);

        $now = date('Y-m-d H:i:s');
        $diskusi = new Diskusi();
        $diskusi->kategori_diskusi_id = $kategoriDiskusi->id;
        // due to #1815
        // $diskusi->is_anonymous = $validatedRequest["is_anonymous"] ? 1 : 0;
        $diskusi->is_anonymous = 1;
        $diskusi->title = $validatedRequest["judul"];
        $diskusi->user_id = $this->shared->user->um_id;
        $diskusi->tenant_id = -1234;
        $diskusi->content = $validatedRequest["konten_diskusi"];
        $diskusi->link_terkait = $validatedRequest["link_terkait"];
        $diskusi->created_at = $now;
        $diskusi->updated_at = $now;
        $diskusi->type = $type;
        $diskusi->views = 0;

        if ($type == 1) {
            if (!empty($validatedRequest["judul_en"])) {
                $diskusi->title_en = $validatedRequest["judul_en"];
            }
            if (!empty($validatedRequest["konten_diskusi_en"])) {
                $diskusi->content_en = $validatedRequest["konten_diskusi_en"];
            }
        }

        $diskusi->release_date = array_key_exists("release_date", $validatedRequest) ? $validatedRequest["release_date"] : null;

        if (array_key_exists('objek_id', $validatedRequest) && !is_null($validatedRequest["objek_id"])) {
            $diskusi->diskusiObjek = new DiskusiObjek();
            $diskusi->diskusiObjek->objek_id = $validatedRequest["objek_id"];
            $diskusi->diskusiObjek->nama_objek = array_key_exists('nama_objek', $validatedRequest) ? $validatedRequest["nama_objek"] : '-';
            if($validatedRequest['objek_type'] != null) {
                $diskusi->diskusiObjek->objek_type = $validatedRequest['objek_type'];
            }
        }


        $result['res'] = $diskusi->create();

        if ($result['res']) {
            if($type == 1) {
                if(!empty($validatedRequest['tags']) && $validatedRequest['tags'] != null) {
                    $tags = json_decode($validatedRequest['tags'], true);
                    foreach ($tags as $tag) {
                        if(!array_key_exists('id', $tag)) {
                            $tag['id'] = $this->createNewTag($tag['label']);
                        }
                        else if(empty($tag['id']) || $tag['id'] == null || $tag['id'] < 1) {
                            $tag['id'] = $this->createNewTag($tag['label']);
                        }
                        $beritaTags = new BeritaTags();
                        $beritaTags->id_diskusi = $diskusi->id;
                        $beritaTags->id_tags = $tag['id'];
                        $beritaTags->create();
                    }
                }
            }

            $diskusi = Diskusi::findFirst(
                [
                    "id = :id:",
                    "bind" => [
                        "id" => $diskusi->id
                    ]
                ]
            );

            $subFolder =
                'diskusi_attachment' .
                DIRECTORY_SEPARATOR .
                $this->shared->user->um_id .
                DIRECTORY_SEPARATOR .
                $diskusi->id;

            if ($type == 1 && !empty($validatedRequest['captions'])) {
                if (!empty($validatedRequest['captions_en'])) {
                    $diskusi->diskusiAttachment = $this->processDiskusiAttachment($subFolder, $validatedRequest['captions'], $validatedRequest['captions_en']);
                } else {
                    $diskusi->diskusiAttachment = $this->processDiskusiAttachment($subFolder, $validatedRequest['captions']);
                }
            } else {
                $diskusi->diskusiAttachment = $this->processDiskusiAttachment($subFolder);
            }

            $result['res'] = $diskusi->save();
        }

        $diskusiRespon = new DiskusiRespon();
        $diskusiRespon->title = $validatedRequest["judul"];
        $diskusiRespon->id_diskusi = $diskusi->id;
        $diskusiRespon->id_sektor = $kategoriDiskusi->id;
        $diskusiRespon->created_diskusi = $diskusi->created_at;
        $result['saveRespon'] = $diskusiRespon->save();

        $getDiskusi = DiskusiLikeComment::findFirstByIdSektor($kategoriDiskusi->id);
        if (!empty($getDiskusi)) {
            $before = $getDiskusi->jumlah_diskusi;
            $after = $before + 1;
            $getDiskusi->jumlah_diskusi = $after;
            $result['saveDiskusi'] = $getDiskusi->save();
        } else {
            $jmlhDiskusi = new DiskusiLikeComment();
            $jmlhDiskusi->id_sektor = $kategoriDiskusi->id;
            $diskusiTotal = Diskusi::find([
                "conditions" => "kategori_diskusi_id=:id_kategori:",
                "bind" => [
                    "id_kategori" => $kategoriDiskusi->id
                ]
            ]);
            $jmlhDiskusi->jumlah_diskusi = count($diskusiTotal);
            // $jmlhDiskusi->jumlah_like = $getDiskusi->jumlah_like;
            $result['saveDiskusi'] = $jmlhDiskusi->save();
        }

        $result['diskusi'] = $diskusi;
        $result['produk'] = $produk;

        return $result;
    }

    public function notifyStakeHolder($diskusi, $produk, $params, $logger = null)
    {
        try {
            $diskusi = Diskusi::findFirst(
                [
                    "id = :id:",
                    "bind" => [
                        "id" => $diskusi->id
                    ]
                ]
            );

            $diskusi->umUser->jmlh_dukung_crt_mskn++;
            $diskusi->umUser->save();
            $this->sendNotifMention($params, $diskusi);

            $adminIds = Roles::getAdminUserIds();
            $responsibleUserIds = $produk->getResponsibleUserIds();
            $combinedIds = array_unique(array_merge(
                array_values($adminIds),
                array_values($responsibleUserIds)
            ));

            $isKeluhan = $produk->id_index == Produk::PRODUK_ID_BANSOS;

            NotificationHelper::batchSend(
                $combinedIds,
                $diskusi->user_id,
                "memulai " . ($diskusi->type == 0 ? ($isKeluhan ? 'keluhan' : 'diskusi') : 'cerita') . " " . $diskusi->title,
                ($diskusi->type + 1),
                $diskusi->uuid,
                $this->getClickAction(($diskusi->type + 1), $diskusi->uuid),
                NotificationHelper::CATEGORY_DISCUSSION,
                "started " . ($diskusi->type == 0 ? ($isKeluhan ? 'complaint' : 'discussion') : 'story') . " " . $diskusi->title
            );
        } catch (\Exception $e) {
            if ($logger) {
                $additionalData = ['message' => $e->getMessage()];
                LogHelper::logInfo("Notify stakeholder failed", microtime(true), microtime(true), $additionalData, "sentNotif", $logger);
            }
        }
    }

    //Type 0 = konfirmasi
    //Type 1 = followup
    //Type 2 = komentar
    //Type 3 = create
    public function notifyKorwilPemdaUser($diskusiBansos, $type)
    {
        /** @var $diskusiBansos DiskusiBansos */
        $topikType = TopikDiskusiBansos::TYPE_BANSOS;
        try{
            $topikType = $diskusiBansos->TopikDiskusiBansos->type;
        } catch (\Exception $e) {
            // do nothing
        }

        if ($type == self::BANSOS_NOTIFICATION_CONFIRMATION) {
            $adminKeluhanIds = [];
        } else {
            $adminKeluhanIds = $this->getAdminKeluhanUserIds($diskusiBansos);
        }
        $pemdaIds = $this->getPemdaUserIds($diskusiBansos->id_instansi, $topikType);
        $pelaporId = [];
        $originPemdaIds = [];
        if ($type == $this::BANSOS_NOTIFICATION_CONFIRMATION || $type == $this::BANSOS_NOTIFICATION_FOLLOWUP || $type == $this::BANSOS_NOTIFICATION_COMMENT) {
            $pelaporId[] = $diskusiBansos->diskusi->user_id;
            if ($type == $this::BANSOS_NOTIFICATION_COMMENT) {
                $originPemdaIds = $this->getPemdaUserIds($diskusiBansos->id_instansi_origin, $topikType);
            }
        }

        $combinedIds = $combinedIds = array_unique(array_merge(
            array_values($adminKeluhanIds),
            array_values($pemdaIds),
            array_values($pelaporId),
            array_values($originPemdaIds)
        ));

        $currId = $this->shared->user->um_id;

        if (($key = array_search($currId, $combinedIds)) !== false) {
            unset($combinedIds[$key]);
        }

        $notifContent = "";
        $notifContentEn = "";

        if ($type == 0 || $type == 1) {
            $notifContent .= "melakukan " . ($type == 0 ? 'konfirmasi' : 'tindak lanjut') . " keluhan " . $diskusiBansos->diskusi->title;
            $notifContentEn .= "confirmed  " . ($type == 0 ? 'complaint' : 'follow-up') . ' ' . $diskusiBansos->diskusi->title;
        } elseif ($type == 2) {
            $notifContent .= "memberikan komentar dalam keluhan " . $diskusiBansos->diskusi->title;
            $notifContentEn .= "left comment in complaint titled: " . $diskusiBansos->diskusi->title;
        } else {
            $notifContent .= "memulai keluhan " . $diskusiBansos->diskusi->title;
            $notifContentEn .= "create complaint " . $diskusiBansos->diskusi->title;
        }

        NotificationHelper::batchSend(
            $combinedIds,
            $currId,
            $notifContent,
            ($diskusiBansos->diskusi->type + 1),
            $diskusiBansos->diskusi->uuid,
            "diskusi/detail?uuid=" . $diskusiBansos->diskusi->uuid,
            NotificationHelper::CATEGORY_DISCUSSION,
            $notifContentEn
        );
    }

    public function getDiskusiDetailForKonten($uuid)
    {
        $result = Diskusi::query()
            ->columns("Diskusi.id, Diskusi.uuid, Diskusi.title, Diskusi.content, Diskusi.is_anonymous, Diskusi.kategori_diskusi_id,
                            Produk.id as produk_id, DiskusiObjek.objek_id, DiskusiObjek.nama_objek, Diskusi.link_terkait, Diskusi.type, Diskusi.release_date, UmUser.um_id")
            ->join('UmUser', 'Diskusi.user_id = UmUser.um_id')
            ->join('KategoriDiskusi', 'Diskusi.kategori_diskusi_id = KategoriDiskusi.id')
            ->join('Produk', 'KategoriDiskusi.produk_id = Produk.id_index')
            ->leftJoin('DiskusiObjek', 'DiskusiObjek.diskusi_id = Diskusi.id')
            ->where("Diskusi.uuid = :uuid:")
            ->bind(
                [
                    "uuid" => $uuid
                ]
            )
            ->execute()
            ->toArray();

        if (count($result) == 1) {
            $result[0]["attachments"] = array_map(
                function ($v) {
                    $v["filename"] = basename($v["filename"]);
                    return $v;
                },
                DiskusiAttachment::find(
                    [
                        "columns" => "uuid, filename, diskusi_id, id, filetype, caption, created_at",
                        "diskusi_id = :diskusi_id:",
                        "bind" => [
                            "diskusi_id" => $result[0]["id"]
                        ]
                    ]
                )
                    ->toArray()
            );

            if($result[0]['type'] == '1') {
                $diskusi = new Diskusi();
                $diskusi->assign($result[0]);
                $result[0]['tags'] = $diskusi->tags->toArray();
            }

            if (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::MINIO) {
                /** @var MinioService $minioService */
                $minioService = $this->minio;
                foreach ($result[0]['attachments'] as $key => $val) {
                    $subFolder = 'diskusi_attachment' . DIRECTORY_SEPARATOR . $result[0]['um_id'] . DIRECTORY_SEPARATOR . $val['diskusi_id'];
                    $filename = $val['filename'];
                    $filekey = $subFolder . DIRECTORY_SEPARATOR . $filename;

                    $url = $minioService->checkAndDownloadPrivate(
                        LogAttachments::DiskusiAttachment,
                        $val['created_at'],
                        $filekey,
                        $filename,
                        false
                    );

                    $result[0]['attachments'][$key] = [
                        "id" => $val['id'],
                        "uuid" => $val['uuid'],
                        "filename" => $val['filename'],
                        "filetype" => $val['filetype'],
                        "caption" => $val['caption'],
                        "url" => $url
                    ];
                }
            }
        }

        return $result;
    }

    public function editDiskusi($uuid, $params)
    {
        $result = Diskusi::find(
            [
                "uuid = :uuid: and user_id = :user_id:",
                "bind" => [
                    "uuid" => $uuid,
                    "user_id" => $this->shared->user->um_id
                ]
            ]
        );

        if ($result->count() != 1) {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, 'Diskusi tidak ditemukan');
        }

        $diskusi = $result[0];

        if ($diskusi->isDeleted()) {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, 'Diskusi telah dikunci');
        }

        if (!empty($diskusi->report())) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Diskusi telah dilaporkan');
        }

        $this->checkMimeTypes();

        $now = date('Y-m-d H:i:s');
        // due to #1815
        // $diskusi->is_anonymous = $params["is_anonymous"] ? 1 : 0;
        $diskusi->is_anonymous = 1;
        $diskusi->title = $params["judul"];
        $diskusi->content = $params["konten_diskusi"];
        $diskusi->link_terkait = $params["link_terkait"];
        $diskusi->updated_at = $now;

        $this->sendNotifEditDiskusi($diskusi->id, $uuid);

        $this->sendNotifMention($params, $diskusi);

        $subFolder =
            'diskusi_attachment' .
            DIRECTORY_SEPARATOR .
            $this->shared->user->um_id .
            DIRECTORY_SEPARATOR .
            $diskusi->id;

        $this->processRemoveAttachment($subFolder, $params);

        $diskusi->diskusiAttachment = $this->processDiskusiAttachment($subFolder);

        $diskusi->save();

        $res['diskusi'] = $diskusi;

        return $res;
    }

    private function containBlacklist($content)
    {
        #$config = new Config($applicationConfig);
        if (empty($content)) {
            return false;
        }

        $filteredContent = strtolower(preg_replace('/\s/', '', $content));

        foreach ($this->config['blacklist_sequence_list'] as $sequence) {
            $seq = strtolower(preg_replace('/\s/', '', $sequence));

            if (strpos($filteredContent, $seq) !== false) {
                return true;
            }
        }

        return false;
    }

    private function checkUserCreateDiscussionQuota($userId, $quota = 3)
    {
        $now = Carbon::now();
        $startDate = $now->subDays(1)->format('Y-m-d H:i:s.u');

        $count = Diskusi::count([
            'user_id=:user_id: AND created_at < NOW() AND created_at > :start_date:',
            'bind' => [
                'user_id' => $userId,
                'start_date' => $startDate
            ]
        ]);

        if ($count >= $quota) {
            $users = UmUser::findByUmId($userId);

            if (!empty($users) && count($users) > 0) {
                $aWeekAgo = Carbon::now()->subDays(7)->format('Y-m-d H:i:s.u');
                if (
                    !empty($users[0]->id_instansi)
                    || ($users[0]->um_changed_time < $aWeekAgo && $count < 10)
                ) {
                    return;
                }
            }

            $logQuotaError = new LogQuotaError();
            $logQuotaError->user_id = $userId;
            $logQuotaError->created_at = date('Y-m-d H:i:s');
            $logQuotaError->save();

            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Ups! jumlah diskusimu sudah mencapai batas. Besok lagi bikin diskusinya ya');
        }
    }

    private function checkFiles($files, $validationConfig)
    {
        $errors = [];

        $allowedTypes = [
            "image/bmp", "image/x-windows-bmp", "image/jpeg", "image/png", "image/tiff", "image/gif",
            "application/pdf", "application/msword", "application/excel", "application/vnd.ms-excel",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            "application/vnd.ms-powerpoint",
            "application/vnd.ms-office",
        ];
        $maxSizeKB = 10000;
        $maxFileCount = 10;

        if (array_key_exists('allowed-types', $validationConfig)) {
            $allowedTypes = $validationConfig['allowed-types'];
        }
        if (array_key_exists('max-size-kb', $validationConfig)) {
            $maxSizeKB = $validationConfig['max-size-kb'];
        }
        if (array_key_exists('max-file-count', $validationConfig)) {
            $maxFileCount = $validationConfig['max-file-count'];
        }

        if (count($files) > $maxFileCount) {
            array_push($errors, [
                "field" => "file",
                "filename" => '-',
                "message" => "Melebihi jumlah file upload: " . $maxFileCount
            ]);
        }
        foreach ($files as $file) {
            if ($file->getSize() < 1) {
                array_push($errors, [
                    "field" => $file->getKey(),
                    "filename" => "-",
                    "message" => "File kosong"
                ]);
                continue;
            }
            if (!in_array($file->getRealType(), $allowedTypes)) {
                array_push($errors, [
                    "field" => $file->getKey(),
                    "filename" => $file->getName(),
                    "message" => "Tipe file tidak diizinkan: " . $file->getRealType()
                ]);
            }
            if (strlen($file->getName()) > 200) {
                array_push($errors, [
                    "field" => $file->getKey(),
                    "filename" => $file->getName(),
                    "message" => "Panjang maksimal nama file 200 karakter"
                ]);
            }
            if ($file->getSize() > $maxSizeKB * 1024) {
                array_push($errors, [
                    "field" => $file->getKey(),
                    "filename" => $file->getName(),
                    "message" => "Ukuran maksimal file: " . $maxSizeKB . " KB"
                ]);
            }
        }

        if (count($errors) > 0) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Invalid File Upload", $errors);
        }
    }

    private function checkMimeTypes()
    {
        $allowedMimeTypes = [
            "image/bmp", "image/x-windows-bmp", "image/jpeg", "image/png", "image/tiff", "image/gif",
            "application/pdf", "application/msword", "application/excel", "application/vnd.ms-excel",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            "application/vnd.ms-powerpoint",
            "application/vnd.ms-office",
        ];
        $errors = [];
        foreach ($this->request->getUploadedFiles() as $file) {
            if (!in_array($file->getRealType(), $allowedMimeTypes)) {
                array_push($errors, [
                    "field" => "files/images",
                    "filename" => $file->getName(),
                    "message" => "Tipe file (" . $file->getName() . ") tidak diizinkan:" . $file->getRealType()
                ]);
            }
        }

        if (count($errors) > 0) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Invalid Mime Types", $errors);
        }
    }

    private function processDiskusiAttachment($subFolder, $captions = null, $captionsEn = null)
    {
        $attachments = [];
        $random = new \Phalcon\Security\Random();
        $attachmentConfig = [
            'max-file-count' => 3,
            'max-size-kb' => 10000
        ];

        if (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::MINIO) {
            if ($this->request->hasFiles()) {
                $uploadedFiles = $this->request->getUploadedFiles();

                $this->checkFiles($uploadedFiles, $attachmentConfig);

                foreach ($uploadedFiles as $index => $file) {
                    $uuid = $random->uuid();

                    /** @var MinioService $minioService */
                    $minioService = $this->minio;
                    if ($minioService->isSecondaryS3Available()) {
                        $minioService->baseUploadUsingSecondaryS3(
                            $file->getTempName(),
                            $file->getRealType(),
                            true,
                            $subFolder . DIRECTORY_SEPARATOR . $file->getName()
                        );
                    } else {
                        $minioService->base_upload_attachment(
                            $file->getTempName(),
                            $file->getRealType(),
                            true,
                            $subFolder . DIRECTORY_SEPARATOR . $file->getName()
                        );
                    }

                    $caption = is_array($captions) && array_key_exists($index, $captions) ? $captions[$index] : null;
                    $captionEn = is_array($captionsEn) && array_key_exists($index, $captionsEn) ? $captionsEn[$index] : null;

                    $diskusiAttachment = new DiskusiAttachment();
                    $diskusiAttachment->filename = $file->getName();
                    $diskusiAttachment->filetype = $file->getRealType();
                    $diskusiAttachment->uuid = $uuid;
                    $diskusiAttachment->caption = $caption;
                    $diskusiAttachment->caption_en = $captionEn;
                    $attachments[] = $diskusiAttachment;
                }
            }
        } elseif (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::LOCAL) {
            if ($this->request->hasFiles()) {
                $uploadedFiles = $this->request->getUploadedFiles();
                $this->checkFiles($uploadedFiles, $attachmentConfig);
                foreach ($uploadedFiles as $index => $file) {
                    $subPath = getenv('PRIVATE_FOLDER') . $subFolder;

                    if (!file_exists($subPath) && !is_dir($subPath)) {
                        mkdir($subPath, 0770, true);
                    }

                    $filename = $subPath . DIRECTORY_SEPARATOR . $file->getName();
                    $file->moveTo($filename);

                    $caption = is_array($captions) && array_key_exists($index, $captions) ? $captions[$index] : null;
                    $captionEn = is_array($captionsEn) && array_key_exists($index, $captionsEn) ? $captionsEn[$index] : null;

                    $diskusiAttachment = new DiskusiAttachment();
                    $diskusiAttachment->filename = $file->getName();
                    $diskusiAttachment->filetype = mime_content_type($filename);
                    $diskusiAttachment->caption = $caption;
                    $diskusiAttachment->caption_en = $captionEn;
                    $attachments[] = $diskusiAttachment;
                }
            }
        }
        return $attachments;
    }

    public function processCommentAttachment($komentarId)
    {
        if (!$this->shared || !$this->minio || !$this->request) {
            return;
        }

        $subFolder =
            'comment_attachment' .
            DIRECTORY_SEPARATOR .
            $this->shared->user->um_id .
            DIRECTORY_SEPARATOR .
            $komentarId;
        $attachments = [];
        $random = new \Phalcon\Security\Random();

        if (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::MINIO) {
            if ($this->request->hasFiles()) {
                $uploadedFiles = $this->request->getUploadedFiles();

                foreach ($uploadedFiles as $file) {
                    $uuid = $random->uuid();

                    /** @var MinioService $minioService */
                    $minioService = $this->minio;
                    if ($minioService->isSecondaryS3Available()) {
                        $minioService->baseUploadUsingSecondaryS3(
                            $file->getTempName(),
                            $file->getRealType(),
                            true,
                            $subFolder . DIRECTORY_SEPARATOR . $file->getName()
                        );
                    } else {
                        $minioService->base_upload_attachment(
                            $file->getTempName(),
                            $file->getRealType(),
                            true,
                            $subFolder . DIRECTORY_SEPARATOR . $file->getName()
                        );
                    }

                    $commentAttachment = new CommentAttachment();
                    $commentAttachment->filename = $file->getName();
                    $commentAttachment->filetype = $file->getRealType();
                    $commentAttachment->uuid = $uuid;
                    $attachments[] = $commentAttachment;
                }
            }
        } elseif (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::LOCAL) {
            if ($this->request->hasFiles()) {
                foreach ($this->request->getUploadedFiles() as $file) {
                    $subPath = getenv('PRIVATE_FOLDER') . $subFolder;

                    if (!file_exists($subPath) && !is_dir($subPath)) {
                        mkdir($subPath, 0770, true);
                    }

                    $filename = $subPath . DIRECTORY_SEPARATOR . $file->getName();
                    $file->moveTo($filename);

                    $commentAttachment = new CommentAttachment();
                    $commentAttachment->filename = $file->getName();
                    $commentAttachment->filetype = mime_content_type($filename);
                    $attachments[] = $commentAttachment;
                }
            }
        }
        return $attachments;
    }

    private function sendNotifMention($params, $diskusi)
    {
        if (array_key_exists('mentions', $params) && !empty($params["mentions"])) {
            if (is_string($params["mentions"])) {
                try {
                    $mentions = json_decode($params["mentions"]);
                    if (!is_array($mentions)) {
                        $mentions = explode(",", $mentions);
                    }
                } catch (\Exception $e) {
                    $mentions = [];
                }
                $mentions = array_unique($mentions);
            } elseif (is_array($params["mentions"])) {
                $mentions = array_unique($params["mentions"]);
            } else {
                $mentions = [];
            }
            foreach ($mentions as $mention) {
                $diskusiMentionUser = new DiskusiMentionUser();
                $diskusiMentionUser->user_id = $this->shared->user->um_id;
                $diskusiMentionUser->tenant_id = -1234;
                $diskusiMentionUser->user_mentioned_id = $mention;
                $diskusiMentionUser->tenant_mentioned_id = -1234;
                $diskusiMentionUser->diskusi_id = $diskusi->id;
                $diskusiMentionUser->create();

                if ($diskusi->type == 0) {
                    $type = "diskusi";
                    $typeEn = "discussion";
                } else {
                    $type = "cerita sukses";
                    $typeEn = "success story";
                }

                $bodyId = "menyebut Anda dalam " . $type . " " . $params["judul"];
                $bodyEn = "mentioned you in a comment in " . $typeEn . " " . $params["judul"];
                $this->sendNotif($mention, $this->shared->user->um_id, $bodyId, ($diskusi->type + 1), $diskusi->uuid, $bodyEn);
            }
        }
    }

    private function getClickAction($action, $uuid)
    {
        $clickAction = "";
        if ($action == NotificationHelper::ACTION_DISKUSI) {
            $clickAction = "diskusi";
        } else {
            $clickAction = "cerita";
        }

        $clickAction .= "/detail?uuid=" . $uuid;

        return $clickAction;
    }

    private function getAdminKeluhanUserIds($diskusiBansos)
    {
        $strWhere = "um_id in (
                            select a.user_id from UsersRoles a
                            where a.deleted_at is null and a.role_id in (
                                select b.role_id from RolesScopes b
                                where b.deleted_at is null and b.scope_id in (
                                    select c.id from Scopes c
                                    where c.deleted_at is null and lower(c.name) in (:required_scopes:)
                                )
                            )
                        )";

        $bind['required_scopes'] = "bansos.confirm_all";
        $korwilUsers = UmUser::find(
            [
                $strWhere,
                "bind" => $bind
            ]
        );

        $korwilIds = [];
        foreach ($korwilUsers as $korwilUser) {
            $korwilIds[] = $korwilUser->um_id;
        }

        return $korwilIds;
    }

    private function getPemdaUserIds($idInstansi, $topikType = TopikDiskusiBansos::TYPE_BANSOS)
    {
        $strWhere = "id_instansi = :id_instansi: and
        um_id in (
            select a.user_id from UsersRoles a
            where a.deleted_at is null and a.role_id in (
                select b.role_id from RolesScopes b
                where b.deleted_at is null and b.scope_id in (
                    select c.id from Scopes c
                    where c.deleted_at is null and lower(c.name) in ({required_scopes:array})
                )
            )
        )";

        $bind['id_instansi'] = $idInstansi;
        switch ($topikType) {
            case(TopikDiskusiBansos::TYPE_DESA):
                $bind['required_scopes'] = ["keluhan.desa.follow_up"];
                break;
            case(TopikDiskusiBansos::TYPE_IKN):
                $bind['required_scopes'] = ["keluhan.ikn.follow_up"];
                break;
            case(TopikDiskusiBansos::TYPE_KAMPUS):
                $bind['required_scopes'] = ["keluhan.kampus.follow_up"];
                break;
            case(TopikDiskusiBansos::TYPE_PELABUHAN):
                $bind['required_scopes'] = ["keluhan.pelabuhan.follow_up"];
                break;
            case(TopikDiskusiBansos::TYPE_BPJS_KESEHATAN):
                $bind['required_scopes'] = ["keluhan.bpjs.follow_up"];
                break;
            case(TopikDiskusiBansos::TYPE_PENDIDIKAN):
                $bind['required_scopes'] = ["keluhan.pendidikan.follow_up"];
                break;
            default:
                $bind['required_scopes'] = ["bansos.follow_up"];
                break;
        }
        $pemdaUsers = UmUser::find(
            [
                $strWhere,
                "bind" => $bind
            ]
        );

        $pemdaIds = [];
        foreach ($pemdaUsers as $pemdaUser) {
            $pemdaIds[] = $pemdaUser->um_id;
        }

        return $pemdaIds;
    }

    private function sendNotifEditDiskusi($diskusiId, $uuid)
    {
        $result = DiskusiMentionUser::query()
            ->columns("UmUser.um_user_name as nama, DiskusiMentionUser.user_mentioned_id, Diskusi.title, Diskusi.type")
            ->join('UmUser', 'DiskusiMentionUser.user_id = UmUser.um_id')
            ->join('Diskusi', 'DiskusiMentionUser.diskusi_id = Diskusi.id')
            ->where("DiskusiMentionUser.diskusi_id = :diskusi_id:")
            ->bind(
                [
                    "diskusi_id" => $diskusiId
                ]
            )
            ->execute()
            ->toArray();

        foreach ($result as $res) {
            $bodyId = "mengubah konten diskusi " . $res["title"];
            $bodyEn = "changed discussion content " . $res["title"];
            $this->sendNotif($res["user_mentioned_id"], $this->shared->user->um_id, $bodyId, ($res["type"] + 1), $uuid, $bodyEn);
        }
    }

    private function processRemoveAttachment($subFolder, $params)
    {
        if (array_key_exists('deleted_attachments', $params)) {
            if (strlen($params["deleted_attachments"]) > 0) {
                $daArr = explode(",", $params["deleted_attachments"]);
                foreach ($daArr as $da) {
                    $result = DiskusiAttachment::find(
                        [
                            "uuid = :uuid:",
                            "bind" => [
                                "uuid" => $da
                            ]
                        ]
                    );

                    if ($result->count() == 1) {
                        $att = $result[0];

                        if (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::LOCAL) {
                            $filename = getenv('PRIVATE_FOLDER') . $subFolder . DIRECTORY_SEPARATOR . $att->filename;

                            if (file_exists($filename)) {
                                unlink($filename);
                            }
                        } elseif (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::MINIO) {
                            /** @var MinioService $minioService */
                            $minioService = $this->minio;
                            if ($minioService->isSecondaryS3Available()) {
                                $minioService->deleteUsingSecondaryS3($att->filename, true, $subFolder);
                            } else {
                                $minioService->delete($att->filename, true, $subFolder);
                            }
                        }

                        $result->delete();
                    }
                }
            }
        }
    }


    private function sendNotif($userId, $senderUserId, $body, $action, $actionId, $bodyEn)
    {
        $clickAction = $this->getClickAction($action, $actionId);

        NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, NotificationHelper::CATEGORY_DISCUSSION, $bodyEn);
    }

    public static function generateSitemap($logger, $publicPath) {
        try {
            $beritas = Diskusi::find([
                "conditions" => "type = 1 AND is_deleted = 0",
                "order" => "updated_at desc"
            ]);

            $baseUrl = getenv("WEB_BASE_URL");
            $xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"UTF-8\" ?><urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"></urlset>");

            foreach ($beritas as $berita) {
                $uuid = $berita->uuid;
                $title = preg_replace("/\s+/", "-", preg_replace("/[^a-zA-Z ]/", "", strtolower($berita->title)));
                try {
                    $lastmod = new DateTime($berita->updated_at);
                } catch (\Exception $e) {
                    $lastmod = new DateTime();
                }
                $url = $xml->addChild("url");
                $url->addChild("loc", "$baseUrl/berita/$uuid/$title");
                $url->addChild("lastmod", $lastmod->format("Y-m-d"));
            }

            $filename = "sitemap.xml";
            $xml->saveXML("$publicPath/files/$filename");
        } catch (\Exception $e) {
            $additionalData = ['message' => $e->getMessage()];
            LogHelper::logInfo("Generate Sitemap.xml failed", microtime(true), microtime(true), $additionalData, "generateSitemap", $logger);
        }
    }
}
