<?php
class UserHelper
{

    public static function validateUsername($username)
    {
        if (strlen($username) < 6) {
            return 1; // ???
        }

        if (!preg_match('/^[a-zA-Z0-9_\.-]+$/', $username)) {
            return 2; // ???
        }

        $result = UmUser::findFirst(
            [
                "lower(um_user_name) = :username: and is_active = true",
                "bind" => [
                    "username" => strtolower($username)
                ]
            ]
        );

        if ($result)
            return 3; // ???

        return 0;
    }


    public static function generateUsernameForEmail($email, $nama)
    {
        $fragments = explode('@', $email);
        $seed = count($fragments) > 1 ? $fragments[0] : $nama;

        $candidate = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $seed);
        $status = 100;


        while ($status != 0) {

            $status = self::validateUsername($candidate);

            if ($status != 0) {
                $candidate = $candidate . '1';
            }
        }

        return $candidate;
    }

    public static function validateUsernameAvailability($username, $ignore = null, $blacklist = true)
    {
        if (!empty($ignore) && ($username == $ignore)) {
            return $username;
        }
        if ($blacklist) {
            self::validateBlacklistedUsername($username);
        }

        if (self::notAvailableUsername($username)) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                "Username has been used"
            );
        }

        return $username;
    }

    public static function isUsernameAvailable($username, $ignore = null, $blacklist = true) {
        if (!empty($ignore) && ($username == $ignore)) {
            return true;
        }
        if($blacklist) {
            $blacklistedUsername = [
                'JAGA',
                'JAGA.ID',
                'JAGA-ID',
                'PENJAGA',
                'PEN-JAGA',
                'PEN.JAGA',
                'ADMINJAGA',
                'ADMIN-JAGA ',
                'ADMIN.JAGA',
                'WWW.JAGA.ID',
                'WWW-JAGA-ID',
                'WWWJAGAID'
            ];

            foreach ($blacklistedUsername as $blacklistitem) {
                if (strtolower(trim($blacklistitem)) == strtolower(trim($username))) {
                    return false;
                }
            }
        }

        $result = UmUser::query()
            ->where('lower(um_user_name) = :username: and is_active = true')
            ->bind(['username' => strtolower($username)])
            ->limit(1)
            ->execute();
        if($result->count() > 0)  return false;
        return true;
    }

    public static function isEmailAvailable($email, $ignore = null) {
        if (!empty($ignore) && ($email == $ignore)) {
            return true;
        }

        $result = UmUser::query()
            ->where('lower(email) = :email: and is_active = true')
            ->bind(['email' => strtolower($email)])
            ->limit(1)
            ->execute();
        if($result->count() > 0)  return false;
        return true;
    }

    public static function validateBlacklistedUsername($value)
    {
        $blacklistedUsername = [
            'JAGA',
            'JAGA.ID',
            'JAGA-ID',
            'PENJAGA',
            'PEN-JAGA',
            'PEN.JAGA',
            'ADMINJAGA',
            'ADMIN-JAGA ',
            'ADMIN.JAGA',
            'WWW.JAGA.ID',
            'WWW-JAGA-ID',
            'WWWJAGAID'
        ];

        foreach ($blacklistedUsername as $username) {
            if (strtolower(trim($username)) == strtolower(trim($value))) {
                throw new \CustomErrorException(
                    \BaseResponse::INVALID_REQUEST,
                    'Invalid username'
                );
            }
        }
    }

    public static function validateBlacklistedEmail($email)
    {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return false;
        }

        $parts = explode('@', $email);
        $domainPart = $parts[1];

        // Validasi bagian setelah "@": hanya huruf, "-" dan "." (TIDAK BOLEH ADA ANGKA)
        if (!preg_match('/^[a-zA-Z.\-]+$/', $domainPart)) {
            return false;
        }

        return !in_array(strtolower($domainPart), (new UserHelper)->blacklistedEmail(), true);
    }

    public static function validateEmailAvailability($email, $ignore = null)
    {
        if (!empty($ignore) && ($email == $ignore)) {
            return $email;
        }

        if (self::notAvailableEmail($email)) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                "Email has been used"
            );
        }

        return $email;
    }

    public static function validatePhoneAvailability($phone, $ignore = null)
    {
        if (!empty($ignore) && ($phone == $ignore)) {
            return $phone;
        }
        if (self::notAvailablePhone($phone)) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                "Phone number has been used"
            );
        }

        return $phone;

    }

    public static function notAvailableUsername($username)
    {
       $result = UmUser::query()
            ->where('lower(um_user_name) = :username: and is_active = true')
            ->bind(['username' => strtolower($username)])
            ->limit(1)
            ->execute();

        return $result->count() > 0;
    }

    public static function notAvailableEmail($email)
    {
        $result = UmUser::query()
            ->where('lower(email) = :email: and is_active = true')
            ->bind(['email' => strtolower($email)])
            ->limit(1)
            ->execute();

        return $result->count() > 0;
    }

    public static function notAvailablePhone($phone)
    {
        $result = UmUser::query()
            ->where('phone = :phone: and is_active = true')
            ->bind(['phone' => $phone])
            ->limit(1)
            ->execute();

        return $result->count() > 0;
    }

    public static function markDeletedUsername($username, $time) {
        $seed = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
        shuffle($seed);
        $rand = '';
        foreach (array_rand($seed, 5) as $k) {
            $rand .= $seed[$k];
        };

        return $username . ".deleted." . $time;
    }

    public static function markDeletedEmail($email, $time) {
        $seed = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
        shuffle($seed);
        $rand = '';
        foreach (array_rand($seed, 5) as $k) {
            $rand .= $seed[$k];
        };

        $arr = explode("@", $email);
        $res = $email;
        if (count($arr) === 2) {
            $res = $arr[0] . ".deleted." . $time . "@" . $arr[1];
        }

        return $res;
    }

    public static function markDeletedPhone($phone, $time) {
        return $phone . ".deleted." . $time;
    }

    public static function deletion(UmUser $user) {
        // pengecekan kondisi user valid untuk dihapus
        if (!$user->is_active) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "User telah dihapus/tidak aktif");
        }
        if ($user->hasRole('admin_sistem')) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "User memiliki role Admin Sistem");
        }

        // soft delete akun & ubah username (untuk handle username unique, sehingga username lama bisa digunakan utk register)
        $time = time();
        $user->is_active = false;
        $user->um_user_name = UserHelper::markDeletedUsername($user->um_user_name, $time);
        $user->email = UserHelper::markDeletedEmail($user->email, $time);
        $user->phone = UserHelper::markDeletedPhone($user->phone, $time);
        $res = $user->save();
        if (!$res) {
            throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($user));
        }

        $params = [
            "conditions" => "user_id = :um_id:",
            "bind" => [
                "um_id" => $user->um_id
            ]
        ];
        // soft delete diskusi
        $diskusis = Diskusi::find($params);
        foreach ($diskusis as $diskusi) {
            $diskusi->is_deleted = 1;
            $res = $diskusi->save();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($diskusi));
            }
        }
        // soft delete komentar
        $komentars = DiskusiComment::find($params);
        foreach ($komentars as $komentar) {
            $komentar->is_deleted = 1;
            $res = $komentar->save();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($komentar));
            }
        }
        // hard delete like diskusi
        $likes = DiskusiLike::find($params);
        foreach ($likes as $like) {
            $res = $like->delete();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($like));
            }
        }
        // hard delete like komentar
        $komenLikes = DiskusiCommentLike::find($params);
        foreach ($komenLikes as $komenLike) {
            $res = $komenLike->delete();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($komenLike));
            }
        }
        // hard delete share diskusi
        $shares = DiskusiShare::find($params);
        foreach ($shares as $share) {
            $res = $share->delete();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($share));
            }
        }
        // hard delete laporan yg dibuat
        $laporans = DiskusiLapor::find([
            "conditions" => "id_user = :um_id:",
            "bind" => [
                "um_id" => $user->um_id
            ]
        ]);
        foreach ($laporans as $laporan) {
            $res = $laporan->delete();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($laporan));
            }
        }
        // hard delete fcm_device_token
        $fcms = FcmDeviceToken::find($params);
        foreach ($fcms as $fcm) {
            $res = $fcm->delete();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($fcm));
            }
        }
        // revoke jwt_data
        $jwts = JwtData::find($params);
        foreach ($jwts as $jwt) {
            $jwt->status = JwtData::STATUS_REVOKED;
            $res = $jwt->save();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($jwt));
            }
        }
        // soft delete korwil_team_user
        $ktus = KorwilTeamUser::find($params);
        foreach ($ktus as $ktu) {
            $res = $ktu->delete();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($ktu));
            }
        }
        // soft delete users_sekolah
        $uss = \Jaga\Models\UsersSekolah::find(['conditions' => 'um_id = :id:', 'bind' => ['id' => $user->um_id]]);
        foreach ($uss as $us) {
            $res = $us->delete();
            if (!$res) {
                throw new CustomErrorException(BaseResponse::SQL_ERROR, self::getModelErrors($us));
            }
        }
        // soft delete pancek_user, pancek_instansi, pancek_formulir
        /** @var PancekUser|false $pu */
        $pu = PancekUser::findFirst(['conditions' => 'um_id = :id:', 'bind' => ['id' => $user->um_id]]);
        if ($pu) {
            try {
                $pu->deletion();
            } catch (CustomErrorException $e) {
                throw $e;
            }
        }
    }

    public static function getModelErrors($model) {
        $errors = $model->getMessages();
        $error_messages = [];

        foreach ($errors as $key => $error) {
            $error_messages[] = ["field" => $error->getField(), "message" => $error->getMessage()];
        }

        return $error_messages;
    }

    public static function validateProfilePicture($files)
    {
        $errors = [];

        $validationConfig = [
            'allowed-types' => ["image/jpg", "image/bmp", "image/x-windows-bmp", "image/jpeg", "image/png", "image/tiff", "image/gif"],
            'max-file-count' => 1,
            'max-size-kb' => 1024
        ];

        $allowedTypes = $validationConfig['allowed-types'];
        $maxSizeKB = $validationConfig['max-size-kb'];
        $maxFileCount = $validationConfig['max-file-count'];

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

    public static function reqVerifyEmail(UmUser $umUser, $emailAddress, MailHelper $mailHelper, $webBaseUrl)
    {
        $verifCode = ReqUmUserEmail::reqVerify($umUser, $emailAddress);
        $subject = "[JAGA] Verifikasi Email Akun JAGA";
        $message = "
                <div style='font-family: Roboto,Open Sans,sans-serif'>
                    <h4>Hi Sahabat JAGA, terima kasih telah menggunakan Aplikasi JAGA.</h4>
                    <p>Klik tombol berikut untuk melakukan verifikasi email yang kamu gunakan:</p>
                    <div style='text-align: center'>
                        <a href='" . $webBaseUrl . "/email-verification?code=" . $verifCode . "' style='background-color: #ed1c24; border-radius: .5rem; cursor: pointer;display: inline-flex; flex-direction: column; align-items: stretch; position: relative; outline: 0; border: 0; vertical-align: middle; padding: 8px 11px; font-size: 14px; line-height: 1.715em; text-decoration: none; color: white; font-weight: 500; text-transform: uppercase; text-align: center; width: auto; height: auto'>
                            VERIFIKASI EMAIL
                        </a>
                    </div>
                    <p>atau akses link berikut " . $webBaseUrl . "/email-verification?code=" . $verifCode . "</p>
                    <p>Bila ada kendala, hubungi WA JAGA (0811 989 7494) atau gunakan fitur chat pada situs jaga.id.</p>
                    <p>Akses JAGA dan bantu kami untuk Cegah Korupsi dari Ujung Jari.</p>
                    <p>Perhatian: E-mail ini (termasuk seluruh lampirannya, bila ada) dikirim otomatis oleh aplikasi dan hanya ditujukan kepada penerima yang tercantum di atas. Jika Anda bukan penerima yang dituju, maka Anda tidak diperkenankan untuk memanfaatkan, menyebarkan, mendistribusikan, atau menggandakan e-mail ini beserta seluruh lampirannya. Mohon untuk tidak membalas email ini.</p>
                </div>
            ";
        $mailHelper->queue($emailAddress, $subject, $message, true, $umUser->um_id);
    }

    private function blacklistedEmail()
    {
        return [
            "aladeen.org",
            "yopmail.com",
            "ishyp.com",
            "bvzoonm.com",
            "bk.ru",
            "mail.xyz",
            "mail.ru",
            "mail.com",
            "mail.id",
            "mailinator.com",
            "spambox.me",
            "post.com",
            "epppl.com",
            "evodok.com",
            "exdonuts.com",
            "foxja.com",
            "gxmer.com",
            "hustletussle.com",
            "klepf.com",
            "lihe555.com",
            "lompaochi.com",
            "lostandalone.com",
            "magim.be",
            "marmaryta.life",
            "maryon.net",
            "mixely.com",
            "mrramtruck.com",
            "netoiu.com",
            "nezid.com",
            "npo2.com",
            "officemalaga.com",
            "onekisspresave.com",
            "pedode.com",
            "politician.com",
            "programmer.net",
            "psncl.com",
            "pzask.com",
            "seek4wap.com",
            "goomail.club",
            "cloudtestlabaccounts.com",
            "sangkuriang.co.id",
            "xxx@xxx.com",
            "zslsz.com",
            "akmtop.com",
            "atomicmail.io",
            "bangalorefoodfete.com",
            "bartender.net",
            "bcaoo.com",
            "cndps.com",
            "cuoly.com",
            "dalebig.com",
            "dayrep.com",
            "dhamsi.com",
            "digiwr.com",
            "digiwr.xyz",
            "doramail.com",
            "duck.com",
            "etlgr.com",
            "forexzig.com",
            "girtipo.com",
            "gisiul.com",
            "gmx.us",
            "yandex.com",
            "xitudy.com",
            "xbreg.com",
            "vusra.com",
            "vreaa.com",
            "vomoto.com",
            "vivaldi.net",
            "tuta.io",
            "ttirv.net",
            "trythe.net",
            "tovinit.com",
            "thepacbook.com",
            "tfbnw.net",
            "tempmail.de",
            "stayhome.li",
            "somelora.com",
            "snakebite.com",
            "ravemail.com",
            "proton.me",
            "protonmail.com",
            "mailnesia.com",
        ];
    }
}
?>
