<?php

use sngrl\PhpFirebaseCloudMessaging\Notification;

class ActivityService
{
    private $shared;
	private $logger;

    public function __construct($shared,$logger)
    {
        $this->shared = $shared;
		$this->logger = $logger;
    }

    public function createActivity($produkId, $objekId, $diskusiId = 0)
    {
        if (
            !empty($produkId)
            && !empty($this->shared)
            && !empty($this->shared->user)
            && !empty($this->shared->user->um_id)
        ) {
            $objekId = empty($objekId) || is_null($objekId) ? "0" : $objekId;

            $produk = Produk::findFirst(
                [
                    "id_index = :produk_id:",
                    "bind" => [
                        "produk_id" => $produkId
                    ]
                ]
            );

            if (empty($produk)) {
                return;
            }

            $activity = new UserActivity();
            $activity->user_id = $this->shared->user->um_id;
            $activity->produk_id = $produkId;
            $activity->objek_id = $objekId;
            $activity->diskusi_id = $diskusiId;
            $activity->latitude = '';
            $activity->longitude = '';

            $result = $activity->create();

            if ($result && $objekId != '0' && $objekId != '-1') {
                $activityMatrix = ActivityKeyMatrix::findFirst(
                    [
                        "produk_id = :produk_id: and objek_id = :objek_id: and deleted_at is null",
                        "bind" => [
                            "produk_id" => $produkId,
                            "objek_id" => $objekId
                        ]
                    ]
                );

                if (empty($activityMatrix)) {
                    $keluhanType = null;
                    if ($diskusiId > 0) {
                        $keluhan = DiskusiBansos::findFirst('id_diskusi = ' . $diskusiId);
                        if ($keluhan) {
                            $keluhanType = $keluhan->TopikDiskusiBansos->type;
                        }
                    }
                    $this->createActivityKeyMatrix($produkId, $objekId, $keluhanType);
                }
            }
        }
    }

    public function processRecomendation()
    {
		$action = "Process Recommendation\n";
		$logMessage = "";
		$startTime = microtime(true);

        $trendingDiskusi = NULL;
        $result = [];
        $userList = UserActivity::query()
            ->columns("DISTINCT user_id")
            ->execute();

        $arrObject = [];
        $userCount = 0;
        $userCountOld = 0;

        #region Get Normal Recommendation

        foreach ($userList as $user) {
            $activityData = UserActivity::query()
                ->columns("UserActivity.user_id, UserActivity.produk_id, UserActivity.objek_id, count(UserActivity.user_id) AS total, Matrix.key_1, Matrix.key_2, Matrix.key_3")
                ->join('ActivityKeyMatrix', 'UserActivity.produk_id = Matrix.produk_id AND UserActivity.objek_id = Matrix.objek_id', 'Matrix')
                ->where('user_id = :user_id: and UserActivity.produk_id <> :produk_id: and UserActivity.deleted_at is null and Matrix.deleted_at is null')
                ->bind(['user_id' => $user["user_id"], 'produk_id' => UserActivity::PRODUK_UMUM])
                ->groupBy("user_id,UserActivity.produk_id, UserActivity.objek_id, key_1, key_2, key_3")
                ->orderBy("total DESC")
                ->limit(20)
                ->execute()
                ->toArray();
            //where last 20 activities

            $i = 1;

            if (count($activityData) > 0) {
                $userCount++;
                $object['user_id'] = $user->user_id;
                $object['recommend_object'] = [];
                $listDiskusiUUIDAlreadyAdded = [];

                while ($i <= 2) {
                    foreach ($activityData as $activity) {
                        //Get Kategori Diskusi
                        $arrKategoriDiskusi = $this->createListStringKategoriProduk($activity['produk_id']);

                        //Get object-related discussion
                        $arrDiskusiId = $this->createListStringDiskusiObjek($activity, $i);

                        if (count($arrDiskusiId) > 0) {
                            $bind["kategori_diskusi"] = $arrKategoriDiskusi;
                            $bind["diskusi_id"] = $arrDiskusiId;
                            $bind["user_id"] = $user["user_id"];
                            $bind["is_deleted"] = 0;
                            $bind['limit_date'] = date('Y-m-d', strtotime('-3 month'));

                            $listDiskusi = Diskusi::query()
                                ->columns("*")
                                ->where("is_deleted = :is_deleted: AND kategori_diskusi_id IN ({kategori_diskusi:array})
                                AND id not in (SELECT diskusi_id from UserActivity where UserActivity.user_id = :user_id: AND UserActivity.deleted_at is null)
                                AND id IN ({diskusi_id:array})
                                AND created_at > :limit_date:")
                                ->bind($bind)
                                ->orderBy("views DESC")
                                ->execute()
                                ->toArray();

                            if (count($listDiskusi) > 0) {
                                foreach ($listDiskusi as $diskusi) {
                                    if (!in_array($diskusi['uuid'], $listDiskusiUUIDAlreadyAdded)) {
                                        $recommObject["produk_id"] = $activity['produk_id'];
                                        $recommObject["objek_id"] = $activity['objek_id'];
                                        $recommObject["iteration"] = "Key " . $i;
                                        $recommObject["diskusi"] = $diskusi;
                                        $recommObject["diskusi_uuid"] = $diskusi["uuid"];

                                        $object['recommend_object'][] = $recommObject;
                                        $listDiskusiUUIDAlreadyAdded[] = $diskusi['uuid'];
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    $i++;
                }

                $object['count_diskusi'] = count($object['recommend_object']);
                $object['tipe_rekomendasi'] = RecommendationContainer::RECOMMENDATION_COLLECTION;
                $arrObject[] = $object;
            }
        }

        //Delete Recommendation Container
        $datas = RecommendationContainer::find();
        $datas->delete();

        $this->InsertRecommendationResult($arrObject);
        $this->sendNotif($arrObject);
		$logMessage.="Send " . count($arrObject) . " recommendation notification";
        #endregion

        #region Get Trending Recommendation

        if (getenv("MODUL_REKOMENDASI") == 1) {
            $oldUserIdList = [];
            $newUserIdList = [];
            foreach ($userList as $user) {
                $oldUserIdList[] = $user['user_id'];
            }

            $strUserWhere = "is_banned = :is_banned:";
            $bindUser["is_banned"] = "0";
            if (count($oldUserIdList) > 0) {
                $strUserWhere .= " and um_id not in ({arr_old_users:array})";
                $bindUser["arr_old_users"] = $oldUserIdList;
            }

            $listNewUser = UmUser::query()
                ->columns("um_id")
                ->where($strUserWhere)
                ->bind($bindUser)
                ->execute()
                ->toArray();

            if (count($listNewUser) > 0) {
                $arrObjectOld = [];
                $trendDiskusiId = $this->getDiskusiTrending();
                if ($trendDiskusiId > 0) {
                    $trendingDiskusi = Diskusi::findFirst(
                        [
                            "is_deleted = :is_deleted: and id = :diskusi_id:",
                            "bind" => [
                                "is_deleted" => 0,
                                "diskusi_id" => $trendDiskusiId
                            ]
                        ]
                    )->toArray();

                    foreach ($listNewUser as $newUser) {
                        $userCountOld++;
                        $object['user_id'] = $newUser['um_id'];
                        $object['recommend_object'][] = $trendingDiskusi;
                        $object['tipe_rekomendasi'] = RecommendationContainer::RECOMMENDATION_SINGLE;
                        $object['count_diskusi'] = 1;

                        $arrObjectOld[] = $object;
                    }
                }

                $this->sendNotif($arrObjectOld);
				$logMessage.="Send " . count($arrObjectOld) . " trending recommendation notification";
            }
        }

        #endregion

        $endTime = microtime(true);
        $additionalDataLog['user_processed'] = $userCount;
        $additionalDataLog['user_trend_processed'] = $userCountOld;
		LogHelper::logInfo($action . $logMessage, $startTime, $endTime, $additionalDataLog, "processRecomendation", $this->logger);

        $result['user_count'] = $userCount;
        $result['user_count_trend'] = $userCountOld;
        //$result['recommendation'] = $arrObject;
        return $result;
    }



    private function getClickAction($action, $uuid)
    {
        $clickAction = "";

        if ($action == NotificationHelper::ACTION_DISKUSI) {
            $clickAction = "diskusi/detail?uuid=" . $uuid;
        } else if ($action == NotificationHelper::ACTION_RECOMMENDATION) {
            $clickAction = "";
        }

        return $clickAction;
    }

    private function sendNotif($arrObject)
    {

        foreach ($arrObject as $obj) {
            if ($obj['count_diskusi'] > 0) {
                if ($obj['tipe_rekomendasi'] == RecommendationContainer::RECOMMENDATION_SINGLE) {
                    $userId = $obj["user_id"];
                    $action = NotificationHelper::ACTION_DISKUSI;
                    $actionId = $obj["recommend_object"][0]['diskusi']['uuid'];

                    $clickAction = $this->getClickAction($action, $actionId);

                    $body = "Anda mendapatkan rekomendasi diskusi";
                    $bodyEn = "This recommendation[s] is for you";
                } else if ($obj['tipe_rekomendasi'] == RecommendationContainer::RECOMMENDATION_COLLECTION) {
                    $userId = $obj["user_id"];
                    $action = NotificationHelper::ACTION_RECOMMENDATION;
                    $actionId = $obj["user_id"];

                    $clickAction = $this->getClickAction($action, $actionId);

                    $body = "Anda mendapatkan " . $obj['count_diskusi'] . " rekomendasi diskusi";
                    $bodyEn = "You received " . $obj['count_diskusi'] . " discussion recommendation";
                }

                NotificationHelper::sendWithoutSender($userId, $body, $action, $actionId, $clickAction, NotificationHelper::CATEGORY_RECOMMENDATION, $bodyEn);
            }
        }
    }

    private function createActivityKeyMatrix($produkId, $objekId, $objekJenis = null)
    {
        $key = [];
        switch ($produkId) {
            case UserActivity::PRODUK_UMUM:
                $key = $this->generateKeyMatrixUmum();
                break;
            case UserActivity::PRODUK_PENDIDIKAN:
                $key = $this->generateKeyMatrixPendidikan($objekId);
                break;
            case UserActivity::PRODUK_KESEHATAN:
                $key = $this->generateKeyMatrixKesehatan($objekId);
                break;
            case UserActivity::PRODUK_DESA:
                $key = $this->generateKeyMatrixDesa($objekId);
                break;
            case UserActivity::PRODUK_PERIZINAN:
                $key = $this->generateKeyMatrixPerizinan($objekId);
                break;
            case UserActivity::PRODUK_BANSOS:
                $key = $this->generateKeyMatrixBansos($objekId, $objekJenis);
                break;
            default:
                $key = $this->generateKeyMatrixDefault();
                break;
        }

        $activityKey = new ActivityKeyMatrix();
        $activityKey->produk_id = $produkId;
        $activityKey->objek_id = $objekId;
        $activityKey->key_1 = $key['key_1'];
        $activityKey->key_2 = $key['key_2'];
        $activityKey->key_3 = $key['key_3'];
        $activityKey->key_4 = $key['key_4'];
        $activityKey->key_5 = $key['key_5'];
        $result = $activityKey->save();

        return $result;
    }

    private function generateKeyMatrixDefault()
    {
        $key['key_1'] = '';
        $key['key_2'] = '';
        $key['key_3'] = '';
        $key['key_4'] = '';
        $key['key_5'] = '';

        return $key;
    }

    private function generateKeyMatrixUmum()
    {
        $key['key_1'] = '';
        $key['key_2'] = '';
        $key['key_3'] = '';
        $key['key_4'] = '';
        $key['key_5'] = '';

        return $key;
    }

    private function generateKeyMatrixPendidikan($npsn)
    {
        $key['key_1'] = '';
        $key['key_2'] = '';
        $key['key_3'] = '';
        $key['key_4'] = '';
        $key['key_5'] = '';

        $sekolah = Sekolah::findFirst(
            [
                "npsn = :npsn:",
                "bind" => [
                    "npsn" => $npsn
                ]
            ]
        );

        if (!empty($sekolah)) {
            $key['key_1'] = $npsn;
            $key['key_2'] = is_null($sekolah->kecamatan) ? '' : $sekolah->kecamatan;
            $key['key_3'] = is_null($sekolah->kota_kab) ? '' : $sekolah->kota_kab;
            $key['key_4'] = is_null($sekolah->provinsi) ? '' : $sekolah->provinsi;
        }

        return $key;
    }

    private function generateKeyMatrixKesehatan($kodeFasKes)
    {
        $key['key_1'] = '';
        $key['key_2'] = '';
        $key['key_3'] = '';
        $key['key_4'] = '';
        $key['key_5'] = '';

        $fasKes = RumahSakit::findFirst(
            [
                "kode_rs = :kode_rs:",
                "bind" => [
                    "kode_rs" => $kodeFasKes
                ]
            ]
        );

        if (empty($fasKes)) {
            $fasKes = Puskesmas::findFirst(
                [
                    "kode_puskesmas = :kode_puskesmas:",
                    "bind" => [
                        "kode_puskesmas" => $kodeFasKes
                    ]
                ]
            );
        }

        if (!empty($fasKes)) {
            $key['key_1'] = $kodeFasKes;
            $key['key_2'] = is_null($fasKes->kab_kota) ? '' : $fasKes->kab_kota;
            $key['key_3'] = is_null($fasKes->provinsi) ? '' : $fasKes->provinsi;
        }

        return $key;
    }

    private function generateKeyMatrixDesa($kodeDesa)
    {
        $key['key_1'] = '';
        $key['key_2'] = '';
        $key['key_3'] = '';
        $key['key_4'] = '';
        $key['key_5'] = '';

        $desa = OmspanMasterDesa::findFirst(
            [
                "kode_desa = :kode_desa:",
                "bind" => [
                    "kode_desa" => $kodeDesa
                ]
            ]
        );

        if (!empty($desa)) {
            $key['key_1'] = $kodeDesa;
            $key['key_2'] = is_null($desa->kode_kecamatan) ? '' : $desa->kode_kecamatan;
            $key['key_3'] = is_null($desa->kode_pemda) ? '' : $desa->kode_pemda;
            $key['key_4'] = is_null($desa->kode_provinsi) ? '' : $desa->kode_provinsi;
        }

        return $key;
    }

    private function generateKeyMatrixPerizinan($idPerizinan)
    {
        $key['key_1'] = '';
        $key['key_2'] = '';
        $key['key_3'] = '';
        $key['key_4'] = '';
        $key['key_5'] = '';

        $perizinan = Perizinan::findFirst(
            [
                "id = :id_perizinan:",
                "bind" => [
                    "id_perizinan" => $idPerizinan
                ]
            ]
        );

        if (!empty($perizinan)) {
            $key['key_1'] = $idPerizinan;
            $key['key_2'] = is_null($perizinan->kota_kab) ? '' : $perizinan->kota_kab;
            $key['key_3'] = is_null($perizinan->provinsi) ? '' : $perizinan->provinsi;
        }

        return $key;
    }

    private function generateKeyMatrixBansos($idInstansi, $objekJenis = null)
    {
        $key['key_1'] = '0';
        $key['key_2'] = '0';
        $key['key_3'] = '0';
        $key['key_4'] = '0';
        $key['key_5'] = '0';

        // untuk keluhan desa, objek merupakan desa
        // selain itu, objek merupakan instansi
        if ($objekJenis === TopikDiskusiBansos::TYPE_DESA) {
            $desa = OmspanMasterDesa::findFirst("id = " . $idInstansi);
            if ($desa) {
                $key['key_1'] = $desa->kode_desa;
                $key['key_2'] = is_null($desa->kode_kecamatan) ? '' : $desa->kode_kecamatan;
                $key['key_3'] = is_null($desa->kode_pemda) ? '' : $desa->kode_pemda;
                $key['key_4'] = is_null($desa->kode_provinsi) ? '' : $desa->kode_provinsi;
            }
        } else {
            $instansi = Instansi::findFirst(
                [
                    "id = :id_instansi: and deleted_at is null",
                    "bind" => [
                        "id_instansi" => $idInstansi
                    ]
                ]
            );

            if ($instansi) {
                $key['key_1'] = $idInstansi;
                $key['key_2'] = is_null($instansi->id_provinsi) ? '' : $instansi->id_provinsi;
            }
        }

        return $key;
    }

    private function createListStringKategoriProduk($produkId)
    {
        $listKategoriDiskusi = KategoriDiskusi::find(
            [
                "produk_id = :produk_id:",
                "bind" => [
                    "produk_id" => $produkId
                ]
            ]
        );
        $arrKategoriDiskusi = [];
        foreach ($listKategoriDiskusi as $kategoriDiskusi) {
            $arrKategoriDiskusi[] = $kategoriDiskusi->id;
        }

        return $arrKategoriDiskusi;
    }

    private function createListStringDiskusiObjek($activity, $iteration)
    {
        $arrObjekId = [];
        //get diskusiObjek

        if ($iteration == 1) {
            $arrObjekId[] = $activity["key_1"];
        } else if ($iteration == 2) {
            if ($activity["key_2"] != '') {
                switch ($activity["produk_id"]) {
                    case UserActivity::PRODUK_PENDIDIKAN:
                        $listSekolah = Sekolah::find(
                            [
                                "kecamatan = :kecamatan:",
                                "bind" => [
                                    "kecamatan" => $activity["key_2"]
                                ]
                            ]
                        );

                        foreach ($listSekolah as $sekolah) {
                            $arrObjekId[] = $sekolah->npsn;
                        }
                        break;
                    case UserActivity::PRODUK_KESEHATAN:
                        $listFasKes = RumahSakit::find(
                            [
                                "kab_kota = :kab_kota:",
                                "bind" => [
                                    "kab_kota" => $activity["key_2"]
                                ]
                            ]
                        );

                        if (count($listFasKes) > 0) {
                            foreach ($listFasKes as $fasKes) {
                                $arrObjekId[] = $fasKes->kode_rs;
                            }
                        } else {
                            $listFasKes = Puskesmas::find(
                                [
                                    "kab_kota = :kab_kota:",
                                    "bind" => [
                                        "kab_kota" => $activity["key_2"]
                                    ]
                                ]
                            );

                            foreach ($listFasKes as $fasKes) {
                                $arrObjekId[] = $fasKes->kode_puskesmas;
                            }
                        }

                        break;
                    case UserActivity::PRODUK_DESA:
                        $listDesa = OmspanMasterDesa::find(
                            [
                                "kode_kecamatan = :kode_kecamatan:",
                                "bind" => [
                                    "kode_kecamatan" => $activity["key_2"]
                                ]
                            ]
                        );

                        foreach ($listDesa as $desa) {
                            $arrObjekId[] = $desa->kode_desa;
                        }
                        break;
                    case UserActivity::PRODUK_PERIZINAN:
                        $listPerizinan = Perizinan::find(
                            [
                                "kota_kab = :kota_kab:",
                                "bind" => [
                                    "kota_kab" => $activity["key_2"]
                                ]
                            ]
                        );

                        foreach ($listPerizinan as $perizinan) {
                            $arrObjekId[] = $perizinan->id;
                        }
                        break;
                    case UserActivity::PRODUK_BANSOS:
                        $listInstansi = Instansi::find(
                            [
                                "id_provinsi = :id_provinsi: and deleted_at is null",
                                "bind" => [
                                    "id_provinsi" => $activity["key_2"]
                                ]
                            ]
                        );

                        foreach ($listInstansi as $instansi) {
                            $arrObjekId[] = $instansi->id;
                        }
                        break;
                    default:
                        $arrObjekId = [];
                }
            }
        }

        $arrDiskusiId = [];

        if (count($arrObjekId)) {
            $listDiskusiObjek = DiskusiObjek::find(
                [
                    "objek_id IN ({objek_id:array})",
                    "bind" => [
                        "objek_id" => $arrObjekId
                    ]
                ]
            );


            foreach ($listDiskusiObjek as $diskusiObjek) {
                $arrDiskusiId[] = $diskusiObjek->diskusi_id;
            }
        }

        return $arrDiskusiId;
    }

    private function getDiskusiTrending()
    {
        $diskusiId = 0;
        $listDiskusi = Diskusi::query()
            ->columns("Diskusi.id, Diskusi.views, count(Comment.id) as CountComment")
            ->leftJoin("DiskusiComment", "Comment.diskusi_id = Diskusi.id", "Comment")
            ->where("Diskusi.is_deleted = :is_deleted:")
            ->bind(["is_deleted" => 0])
            ->groupBy("Diskusi.id, Diskusi.views")
            ->orderBy("CountComment DESC, Diskusi.views DESC")
            ->limit(1)
            ->execute()
            ->toArray();

        if (count($listDiskusi) > 0) {
            $diskusiId = $listDiskusi[0]["id"];
        }


        return $diskusiId;
    }

    private function InsertRecommendationResult($arrObject)
    {
        if (count($arrObject) > 0) {
            foreach ($arrObject as $userObject) {
                if (count($userObject['recommend_object']) > 0) {
                    foreach ($userObject['recommend_object'] as $discussObject) {
                        $recommend = new RecommendationContainer();
                        $recommend->user_id = $userObject['user_id'];
                        $recommend->produk_id = $discussObject['produk_id'];
                        $recommend->diskusi_uuid = $discussObject['diskusi_uuid'];
                        $recommend->create();
                    }
                }
            }
        }
    }
}
