<?php

require_once 'ABaseTest.php';
class UserTest extends BaseTest
{
    const BASE_URL = "user";
    protected $token;
    protected $user_id;

    public function setUp()
    {
        parent::setUp();
        $this->doLogin();
    }

    public function doLogin()
    {
        $login = $this->login(getenv("TEST_ADMIN_USERNAME"), getenv("TEST_ADMIN_PASSWORD"));
        $this->assertContains(
            [
                'success' => true
            ],
            $login,
            "login Failed"
        );
        $user = $login['data'];
        $this->token = $user['token'];
        $this->user_id = $user['user_id'];
    }

    /**
     * @return string[][]
     */
    protected function getHeaders(): array
    {
        return [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->token
            ]
        ];
    }

    public function testAdminListShouldGiveSuccessResponse()
    {
        $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/admin-list',
            $this->getHeaders(),
            200,
            "\nadmin list passed"
        );
    }

    /**
     * require role: stranas.monitoring
     */
    public function testStranasUserListShouldGiveSuccessResponse()
    {
        $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/stranas_list',
            $this->getHeaders(),
            200,
            "stranas user list passed"
        );
    }

    /**
     * require role: admin_korsupgah
     */
    public function testKorwilUserListShouldGiveSuccessResponse()
    {
        $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/korwil_list',
            $this->getHeaders(),
            200,
            "korwil user list passed"
        );
    }

    public function testRegisterUserPublikShouldGiveSuccessResponse()
    {
        $username = 'user.publik.phpunit';
        $expectedResponse = [
            "success" => true,
            "message" => "Berhasil mendaftarkan user"
        ];
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            'auth/register',
            200,
            $expectedResponse,
            "testRegisterUserPublikShouldGiveSuccessResponse passed",
            [
                'multipart' => [
                    ["name" => 'username', "contents" => $username],
                    ["name"=> 'email', "contents" => $username . '@phpunit.com'],
                    ["name"=> 'password', "contents" => '123123'],
                    ["name"=> 'nama', "contents" => 'User Publik PHPUnit'],
                    ["name"=> 'phone', "contents" => '0812' . rand(10000000, 99999999)],
                    ["name"=> 'tempat_lahir', "contents" => 'Bandung'],
                    ["name"=> 'tgl_lahir', "contents" => '1945-08-17'],
                    ["name"=> 'jenis_kelamin', "contents" => 'L'],
                ]
            ]
        );
    }

    /**
     * @depends testRegisterUserPublikShouldGiveSuccessResponse
     */
    public function testRegisterUserPublikShouldGiveErrorUsernameResponse()
    {
        $username = 'USER.PUBLIK.PHPUNIT';
        $expectedResponse = [
            "success" => false,
            'message' => 'Registrasi User Gagal',
            'errors' =>
                array (
                    0 =>
                        array (
                            'field' => 'username',
                            'message' => 'Username has been used.',
                        ),
                ),
        ];
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            'auth/register',
            460,
            $expectedResponse,
            "testRegisterUserPublikShouldGiveErrorUsernameResponse passed",
            [
                'multipart' => [
                    ["name" => 'username', "contents" => $username],
                    ["name"=> 'email', "contents" => $username . rand(0, 99999) . '@phpunit.com'],
                    ["name"=> 'password', "contents" => '123123'],
                    ["name"=> 'nama', "contents" => 'User Publik PHPUnit'],
                    ["name"=> 'phone', "contents" => '0812' . rand(10000000, 99999999)],
                    ["name"=> 'tempat_lahir', "contents" => 'Bandung'],
                    ["name"=> 'tgl_lahir', "contents" => '1945-08-17'],
                    ["name"=> 'jenis_kelamin', "contents" => 'L'],
                ]
            ]
        );
    }

    /**
     * @depends testRegisterUserPublikShouldGiveSuccessResponse
     */
    public function testRegisterUserPublikShouldGiveErrorEmailResponse()
    {
        $username = 'USER.PUBLIK.PHPUNIT';
        $expectedResponse = [
            "success" => false,
            'message' => 'Registrasi User Gagal',
            'errors' =>
                array (
                    0 =>
                        array (
                            'field' => 'email',
                            'message' => 'Email has been used.',
                        ),
                ),
        ];
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            'auth/register',
            460,
            $expectedResponse,
            "testRegisterUserPublikShouldGiveErrorEmailResponse passed",
            [
                'multipart' => [
                    ["name" => 'username', "contents" => $username . rand(0, 99999)],
                    ["name"=> 'email', "contents" => $username . '@phpunit.com'],
                    ["name"=> 'password', "contents" => '123123'],
                    ["name"=> 'nama', "contents" => 'User Publik PHPUnit'],
                    ["name"=> 'phone', "contents" => '0812' . rand(10000000, 99999999)],
                    ["name"=> 'tempat_lahir', "contents" => 'Bandung'],
                    ["name"=> 'tgl_lahir', "contents" => '1945-08-17'],
                    ["name"=> 'jenis_kelamin', "contents" => 'L'],
                ]
            ]
        );
    }

    /**
     * require scope: korsupgah.admin
     */
    public function testRegisterKorwilUserShouldGiveSuccessResponse()
    {
        $observer_korsupgah_role_ids = [12];
        $instansi_id = 1;
        $params = array_merge(
            $this->getHeaders(),
            [
                'json' => [
                    'username' => 'user.korwil.phpunit',
                    'email' => 'user.korwil@phpunit.com',
                    'password' => '123',
                    'confirm_password' => '123',
                    'nama' => 'User Korwil PHPUnit',
                    'phone' => '081290183011',
                    'roles' => $observer_korsupgah_role_ids,
                    'id_instansi' => $instansi_id
                ]
            ]
        );
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            self::BASE_URL . '/register_korwil_user',
            200,
            [
                "success" => true,
                "message" => "Berhasil mendaftarkan user"
            ],
            "korwil user list passed",
            $params
        );
    }

    public function testRegisterKorwilUserShouldGiveErrorUsername()
    {
        $observer_korsupgah_role_ids = [12];
        $instansi_id = 1;
        $params = array_merge(
            $this->getHeaders(),
            [
                'json' => [
                    'username' => 'USER.KORWIL.PHPUNIT',
                    'email' => 'user.korwil2@phpunit.com',
                    'password' => '123123',
                    'confirm_password' => '123123',
                    'nama' => 'User Korwil PHPUnit',
                    'phone' => '08138129012',
                    'roles' => $observer_korsupgah_role_ids,
                    'id_instansi' => $instansi_id
                ]
            ]
        );
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            self::BASE_URL . '/register_korwil_user',
            460,
            [
                "success" => false,
                "message" => "Registrasi User Gagal",
                "errors" => [["field" => "username", "message" => "Username has been used."]]
            ],
            "testRegisterKorwilUserShouldGiveErrorUsername passed",
            $params
        );
    }

    /**
     * require scope: admin.view
     */
    public function testBanShouldGiveSuccessResponse(): array
    {
        $userId = 5;
        $params = array_merge(
            $this->getHeaders(),
            [
                'json' => [
                    'user_id' => $userId
                ]
            ]
        );
        $res = $this->doAPIShouldGiveSubsetResponse(
            'POST',
            self::BASE_URL . '/ban',
            200,
            [
                'success' => true
            ],
            'ban user passed',
            $params
        );

        return $res['data'];
    }

    /**
     * @depends testBanShouldGiveSuccessResponse
     * @param $user
     * require scope: admin.view
     * @return array
     */
    public function testUnbanShouldGiveSuccessResponse($user): array
    {
        $params = array_merge(
            $this->getHeaders(),
            [
                'json' => [
                    'user_id' => $user['um_id']
                ]
            ]
        );
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            self::BASE_URL . '/unban',
            200,
            [
                'success' => true
            ],
            'unban user passed',
            $params
        );

        return $user;
    }

    /**
     * @depends testUnbanShouldGiveSuccessResponse
     * @param $user
     */
    public function testProfilePictureShouldGiveSuccessResponse($user)
    {
        $response = $this->client->request(
            'GET',
            self::BASE_URL . '/propic/' . $user['uuid_user'],
            $this->getHeaders()
        );
        $statusCode = $response->getStatusCode();
        $this->assertEquals(200, $statusCode);
        self::$messages = array_merge(self::$messages, ["profpic passed"]);
    }

    public function testSetRolesShouldGiveSuccessResponse()
    {
        $targetRoleIds = [3, 4, 5, 9];
        $params = array_merge(
            $this->getHeaders(),
            [
                'json' => [
                    'user_id' => $this->user_id,
                    'roles' => $targetRoleIds
                ]
            ]
        );
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            self::BASE_URL . '/set-roles',
            200,
            [
                'success' => true
            ],
            "set roles passed",
            $params
        );
    }

    public function testProfileShouldGiveSuccessResponse()
    {
        $response = $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/profile',
            $this->getHeaders(),
            200,
            "profile passed"
        );

        return $response['data']['result'];
    }

    public function testGetInstansiShouldGiveSuccessResponse()
    {
        $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/instansi',
            $this->getHeaders(),
            200,
            "instansi passed"
        );
    }

    /**
     * @depends testProfileShouldGiveSuccessResponse
     * @param $user
     */
    public function testUbahProfileShouldGiveSuccessResponse($user)
    {
        $params = array_merge(
            $this->getHeaders(),
            [
                'multipart' => [
                    // #988 tidak dapat mengubah username
                    // ['name' => 'username', 'contents' => $user['username']],
                    ['name' => 'nama', 'contents' => $user['nama']],
                    ['name' => 'phone', 'contents' => $user['phone']],
                    ['name' => 'tgl_lahir', 'contents' => $user['tgl_lahir']],
                    ['name' => 'tempat_lahir', 'contents' => $user['tempat_lahir']],
                    ['name' => 'jenis_kelamin', 'contents' => $user['jenis_kelamin']]
                ]
            ]
        );

        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            self::BASE_URL . '/ubah_profile',
            200,
            [
                'success' => true
            ],
            "ubah profile passed",
            $params
        );
    }

    /**
     * @depends testUnbanShouldGiveSuccessResponse
     * @param $user
     */
    public function testPublicProfileShouldGiveSuccessResponse($user)
    {
        $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/public-profile/' . $user['uuid_user'],
            $this->getHeaders(),
            200,
            "public profile passed"
        );
    }

    /**
     * @depends testUnbanShouldGiveSuccessResponse
     * @param $user
     */
    public function testNewPublicProfileShouldGiveSuccessResponse($user)
    {
        $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/public-profile-new/' . $user['uuid_user'],
            $this->getHeaders(),
            200,
            "new public profile passed"
        );
    }

    public function testChangePasswordShouldGiveSuccessResponse()
    {
        $params = array_merge(
            $this->getHeaders(),
            [
                'json' => [
                    'password' => getenv("TEST_ADMIN_PASSWORD"),
                    'new_password' => getenv("TEST_ADMIN_PASSWORD")
                ]
            ]
        );

        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            self::BASE_URL . '/change_password',
            200,
            [
                'success' => true
            ],
            "change password passed",
            $params
        );
    }

    public function testNotificationsShouldGiveSuccessResponse()
    {
        $this->doAPIShouldGiveSuccessResponse(
            'GET',
            self::BASE_URL . '/notifications',
            $this->getHeaders(),
            200,
            "notifications passed"
        );
    }

    public function testNotificationsUnreadCountShouldGiveSuccessResponse()
    {
        $response = $this->client->request('GET', self::BASE_URL . '/notifications/unread_count', $this->getHeaders());
        $statusCode = $response->getStatusCode();
        $jsonResponse = \GuzzleHttp\json_decode($response->getBody(), true);
        $this->assertEquals(200, $statusCode);
        $this->assertArraySubset(
            [
                'status' => 'success'
            ],
            $jsonResponse,
            "notifications unread count failed"
        );
        self::$messages = array_merge(self::$messages, ["notifications unread count passed"]);
    }

    public function testRegisterUserDinasPAK()
    {
        $instansiId = 619;
        $username = 'pak.dinas.prov.jakarta';
        $nama = 'Pemerintah Provinsi DKI Jakarta';

        $params = array_merge(
            $this->getHeaders(),
            [
                'json' => [
                    'username' => $username,
                    'password' => getenv("TEST_ADMIN_PASSWORD"),
                    'confirm_password' => getenv("TEST_ADMIN_PASSWORD"),
                    'id_instansi' => $instansiId,
                    'email' => $username . '@mail.com',
                    'nama' => $nama,
                    'roles' => ['user_dinas_pak'],
                    'phone' => '81000001000',
                    'jenis_kelamin' => 'L'
                ]
            ]
        );
        $this->doAPIShouldGiveSubsetResponse(
            'POST',
            'pak/user/register',
            200,
            [
                "success" => true
            ],
            "testRegisterUserDinasPAK passed",
            $params
        );
    }

    public function testRegisterUserSekolahPAK()
    {
        $sekolah = [
            ['npsn' => '50101684', 'nama' => 'SMAN 2 MENGWI'],
            ['npsn' => '50102004', 'nama' => 'SMAN 1 UBUD'],
            ['npsn' => '50102568', 'nama' => 'SMAN 1 BANGLI'],
            ['npsn' => '50102578', 'nama' => 'SMAN 1 KINTAMANI'],
            ['npsn' => '50102779', 'nama' => 'SMAN 2 AMLAPURA'],
            ['npsn' => '50102780', 'nama' => 'SMAN 1 SIDEMEN'],
            ['npsn' => '50103365', 'nama' => 'SMAN 1 DAWAN'],
            ['npsn' => '50103671', 'nama' => 'SMAN 1 RENDANG'],
            ['npsn' => '50104096', 'nama' => 'SMAN SATU ATAP NUSA PENIDA'],
            ['npsn' => '50105469', 'nama' => 'SMAN 2 MENDOYO'],
        ];

        foreach ($sekolah as $s) {
            $npsn = $s['npsn'];
            $nama = $s['nama'];
            $username = implode(".", explode(" ", $nama));
            $instansiId = 616;

            $params = array_merge(
                $this->getHeaders(),
                [
                    'json' => [
                        'username' => $username,
                        'password' => getenv("TEST_ADMIN_PASSWORD"),
                        'confirm_password' => getenv("TEST_ADMIN_PASSWORD"),
                        'npsn_sekolah' => $npsn,
                        'id_instansi' => $instansiId,
                        'email' => $username . '@mail.com',
                        'nama' => $nama,
                        'roles' => ['user_sekolah_pak'],
                        'phone' => '81000001000',
                        'jenis_kelamin' => 'L'
                    ]
                ]
            );
            $this->doAPIShouldGiveSubsetResponse(
                'POST',
                'pak/user/register',
                200,
                [
                    "success" => true
                ],
                "testRegisterUserSekolahPAK [".$username."] passed",
                $params
            );
        }
    }

    public function testAdminRegisterUser() {
        $response = $this->client->request('GET', 'instansi',
            [
                'query' => [
                    "id_tipe" => 2,
                    "limit" => 1000
                ],
                'headers' => [
                    'Authorization' => 'Bearer ' . $this->token
                ]
            ]
        );

        $statusCode = $response->getStatusCode();
        $jsonResponse = json_decode($response->getBody(), TRUE);
        $this->assertEquals(200, $statusCode);
        $this->assertContains(
            [
                'success' => true
            ],
            $jsonResponse,
            "Error on instansi"
        );
        $instansis = $jsonResponse["data"]["result"];
        foreach ($instansis as $instansi) {
            $nama = explode(" ", $instansi["nama"]);
            array_shift($nama);
            $sub = array_shift($nama);
            $nama = implode($nama, "");
            $multipart = [
                ["name" => "email", "contents" => "admin.".$sub.".".$nama."@mail.com"],
                ["name" => "password", "contents" => "password12345"],
                ["name" => "passwordConfirmation", "contents" => "password12345"],
                ["name" => "nama", "contents" => $instansi["nama"]],
                ["name" => "phone", "contents" => "081241234123"],
                ["name" => "roles", "contents" => "16,72,73,78"],
                ["name" => "image", "contents" => null],
                ["name" => "username", "contents" => "Admin.".$sub."." . $nama],
                ["name" => "id_instansi", "contents" => $instansi["id"]],
            ];
            $response = $this->client->request('POST', 'auth/create',
                [
                    'multipart' => $multipart,
                    'headers' => [
                        'Authorization' => 'Bearer ' . $this->token
                    ]
                ]
            );

            $statusCode = $response->getStatusCode();
            $jsonResponse = json_decode($response->getBody(), TRUE);
            $this->assertEquals(200, $statusCode);
            $this->assertContains(
                [
                    'success' => true
                ],
                $jsonResponse,
                "Error on create " . $nama
            );
        }
    }
}
