<?php

use Phalcon\Mvc\Controller\Base;

class KorwilTeamController extends BaseController
{
    public function list()
    {
        $this->checkIsAuthenticated();

        $getParams = $this->request->get();

        $getParams['limit'] = $this->getDefaultLimit($getParams);
        $getParams['offset'] = array_key_exists('offset', $getParams) ? $getParams['offset'] : 0;
        $getParams['keyword'] = array_key_exists('keyword', $getParams) ? $getParams['keyword'] : '';
        $getParams['id_periode'] = array_key_exists('id_periode', $getParams) ? $getParams['id_periode'] : 0;
        $getParams['id_template'] = array_key_exists('id_template', $getParams) ? $getParams['id_template'] : 0;
        $getParams['order_by'] = array_key_exists('order_by', $getParams) ? strtolower($getParams['order_by']) : 'name';
        $getParams['order_direction'] = array_key_exists('order_direction', $getParams) ? strtolower($getParams['order_direction']) : 'asc';

        $allowed_order = ['id', 'id_periode', 'name', 'id_periode, name'];
        $allowed_order_direction = ['asc', 'desc'];

        $params =  $this->validate(
            $getParams,
            [
                'limit' => ['validators' => ['digit']],
                'offset' => ['validators' => ['digit']],
                'keyword' => ['validators' => []],
                'id_periode' => ['validators' => ['digit']],
                'id_template' => ['validators' => ['digit']],
                'order_by' => ['validators' => [[
                    'name' => 'inclusion_in',
                    'params' => $allowed_order
                ]]],
                'order_direction' => ['validators' => [[
                    'name' => 'inclusion_in',
                    'params' => $allowed_order_direction
                ]]]
            ]
        );

        if ($params['id_template'] > 0) {
            $findPeriodeByIdTemplate = $this->rawQuery("
                SELECT
                    DISTINCT(periode.id)
                FROM
                    korsupgah_periode periode
                LEFT JOIN
                    korsupgah_survey survey ON survey.id_periode = periode.id
                LEFT JOIN
                    korsupgah_template template ON template.id = survey.id_template
                WHERE
                    template.id = ".$params['id_template'].";
		    ");
            if (empty($findPeriodeByIdTemplate)) {
                throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode dengan ID template #' . $params['id_template'] . ' tidak ditemukan');
            }
            $params['id_periode'] = $findPeriodeByIdTemplate[0]['id'];
        }

        $teams = KorwilTeam::find([
            'conditions' => '(name ilike :keyword: OR description ilike :keyword:) AND (id_periode = :id_periode: OR 0 = :id_periode:) AND deleted_at IS NULL',
            'bind' => [
                'keyword' => '%' . $params['keyword'] . '%',
                'id_periode' => $params['id_periode']
            ],
            'limit' => $params['limit'],
            'offset' => $params['offset'],
            'order' =>  $params['order_by'] . ' ' . $params['order_direction']
        ]);

        $result = [];

        foreach ($teams as $team ) {
            $item = $team->toArray();
            $item['nama_periode'] = '';
            if($team->KorsupgahPeriode) {
                $item['nama_periode'] = $team->KorsupgahPeriode->nama;
            }

            $result[] = $item;
        }

        $total_record = KorwilTeam::count();

        return new PaginatedResponse($result, $total_record, $params['limit'], $params['offset']);
    }

    public function update($id)
    {
        $this->checkScopes(['korsupgah.admin']);


        $team = KorwilTeam::findFirst($id);

        if (empty($team)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID #' . $id . 'tidak ditemukan');
        }

        if (!empty($team->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID #' . $id . 'mungkin sudah terhapus');
        }

        $rawBody = $this->request->getJsonRawBody(true);

        $params = $this->validate(
            $rawBody,
            [
                'name' => ['validators' => ['required']],
                'description' => ['validators' => []],
                'id_periode' => ['validators' => ['required','digit']]
            ]
        );

        $periode = KorsupgahPeriode::findFirst($params['id_periode']);

        if (empty($periode)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode Tidak Valid');
        }

        if (!empty($periode->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode [' . $periode->nama . '] mungkin sudah terhapus');
        }

        $team->name = $params['name'];
        $team->description = $params['description'];
        $team->id_periode = $params['id_periode'];
        $team->updated_at = date('Y-m-d H:i:s');
        $status = $team->save();

        if (!$status) {
            $errors = $team->getMessage();

            $error_messages = [];

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

            throw new ValidationsException($error_messages);
        } else {

            return new CollectionPaginatedResponse([$team]);
        }
    }

    public function delete($id)
    {
        $this->checkScopes(['korsupgah.admin']);

        $team = KorwilTeam::findFirst($id);

        if (empty($team)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID #' . $id . 'tidak ditemukan');
        }

        if (!empty($team->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID #' . $id . 'mungkin sudah terhapus');
        }

        $date = date('Y-m-d H:i:s');

        $team->updated_at = $date;
        $team->deleted_at = $date;
        $status = $team->save();

        if (!$status) {
            $errors = $team->getMessages();

            $error_messages = [];

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

            throw new ValidationException($error_messages);
        } else {

            return new CollectionPaginatedResponse([$team]);
        }
    }

    public function create()
    {
        $this->checkScopes(['korsupgah.admin']);

        $rawBody = $this->request->getJsonRawBody(true);

        $params = $this->validate(
            $rawBody,
            [
                'name' => ['validators' => ['required']],
                'description' => ['validators' => []],
                'id_periode' => ['validators' => ['required','digit']],
            ]
        );

        $periode = KorsupgahPeriode::findFirst($params['id_periode']);

        if (empty($periode)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode Tidak Valid');
        }

        if (!empty($periode->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode [' . $periode->nama . '] mungkin sudah terhapus');
        }

        $team = new KorwilTeam();
        $team->name = $params['name'];
        $team->description = $params['description'];
        $team->id_periode = $params['id_periode'];
        $team->created_at = date('Y-m-d H:i:s');
        $status = $team->save();

        if (!$status) {
            $errors = $team->getMessages();

            $error_messages = [];

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

            throw new ValidationException($error_messages);
        } else {
            return new CollectionPaginatedResponse([$team]);
        }
    }

    public function restore($id)
    {
        $this->checkScopes(['korsupgah.admin']);

        $team = KorwilTeam::findFirst($id);

        if (empty($team)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID #' . $id . 'Tidak Ditemukan');
        }

        if (empty($team->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID #' . $id . 'Sudah Aktif');
        }

        $team->updated_at = date('Y-m-d H:i:s');
        $team->deleted_at = null;
        $status = $team->save();

        if (!$status) {
            $errors = $team->getMessages();

            $error_messages = [];

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

            throw new ValidationException($error_messages);
        } else {

            return new CollectionPaginatedResponse([$team]);
        }
    }

    public function syncUsers()
    {
        $this->checkScopes(['korsupgah.admin']);

        $rawBody = $this->request->getJsonRawBody(true);

        $params = $this->validate(
            $rawBody,
            [
                'id' => ['validators' => ['required']],
                'user_ids' => ['validators' => ['required']]
            ]
        );

        if (!is_array($params['user_ids'])) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Format User IDs tidak valid');
        }

        $user_ids = array_unique(array_values($params['user_ids']));

        $team = KorwilTeam::findFirst($params['id']);

        if (empty($team)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Tim tidak ditemukan');
        }

        if (!empty($team->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Data tim sudah terhapus');
        }


        $users = UmUser::find([
            'conditions' => 'um_id in ({ids:array})',
            'bind' => [
                'ids' => array_values($user_ids)
            ]
        ]);

        // Check Expected sub indikator List exists in master data

        $existing_user_ids = [];

        foreach ($users as $key => $user) {
            $existing_user_ids[] = $user->um_id;
        }

        $not_exist_ids = array_diff($user_ids, $existing_user_ids);

        if (!empty($not_exist_ids)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'User dengan ID ' . implode(",", $not_exist_ids) . ' tidak aktif/terdaftar');
        }

        $currentMembers = KorwilTeamUser::find([
            'conditions' => 'team_id=:team_id: AND deleted_at is NULL',
            'bind' => [
                'team_id' => $params['id']
            ]
        ]);


        $current_user_ids = [];

        // Delete all current member that doesn't exist in params
        foreach ($currentMembers as $key => $member) {
            $current_user_ids[] = $member->user_id;
            if (!in_array($member->user_id, $existing_user_ids)) {
                $status = $member->delete();
            }
        }

        $memberStatus = KorwilTeamMemberStatus::find()[0];

        // Otherwise, Register new member to this team
        foreach ($existing_user_ids as $key => $userId) {
            if (!in_array($userId, $current_user_ids)) {
                $member = new KorwilTeamUser();
                $member->team_id = $params['id'];
                $member->user_id = $userId;
                $member->team_member_status_id = $memberStatus->id;

                // $member->team_member_status_id = 1;
                $status = $member->save();
            }
        }

        return new CollectionPaginatedResponse([]);
    }

    public function syncInstansi()
    {
        $this->checkScopes(['korsupgah.admin']);

        $rawBody = $this->request->getJsonRawBody(true);

        $params = $this->validate(
            $rawBody,
            [
                'id' => ['validators' => ['required']],
                'instansi_ids' => ['validators' => ['required']]
            ]
        );

        if (!is_array($params['instansi_ids'])) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Format User IDs tidak valid');
        }

        $instansi_ids = array_unique(array_values($params['instansi_ids']));

        $team = KorwilTeam::findFirst($params['id']);

        if (empty($team)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Tim tidak ditemukan');
        }

        if (!empty($team->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Data tim sudah terhapus');
        }

        
        sort($instansi_ids);
        $string_array_id = implode(", ", $instansi_ids);

        $instansiList = Instansi::find([
            'conditions' => 'id in ({ids:array}) AND deleted_at is NULL',
            'bind' => [
                'ids' => array_values($instansi_ids)
            ]
        ]);

        // Check Expected sub indikator List exists in master data

        $existing_instansi_ids = [];

        foreach ($instansiList as $key => $instansi) {
            $existing_instansi_ids[] = $instansi->id;
        }

        $not_exist_ids = array_diff($instansi_ids, $existing_instansi_ids);

        if (!empty($not_exist_ids)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Instansi dengan ID ' . implode(",", $not_exist_ids) . ' tidak aktif/terdaftar');
        }

        $currentMembers = KorwilTeamInstansi::find([
            'conditions' => 'team_id=:team_id: AND deleted_at is NULL',
            'bind' => [
                'team_id' => $params['id']
            ]
        ]);


        $current_instansi_ids = [];

        // Delete all current member that doesn't exist in params
        foreach ($currentMembers as $key => $member) {
            $current_instansi_ids[] = $member->instansi_id;
            if (!in_array($member->instansi_id, $existing_instansi_ids)) {
                $status = $member->delete();
            }
        }

        // Otherwise, Register new member to this team
        foreach ($existing_instansi_ids as $key => $instansiId) {
            if (!in_array($instansiId, $current_instansi_ids)) {
                $member = new KorwilTeamInstansi();
                $member->team_id = $params['id'];
                $member->instansi_id = $instansiId;
                $status = $member->save();
            }
        }

        return new CollectionPaginatedResponse([]);
    }

    public function detail($id)
    {
        $this->checkIsAuthenticated();

        $team = KorwilTeam::findFirst($id);

        if (empty($team)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team tidak ditemukan');
        }

        $detail = $team->toDetail();

        return new CollectionPaginatedResponse([$detail]);
    }

    public function updateMembershipStatus()
    {
        $this->checkIsAuthenticated();

        $rawBody = $this->request->getJsonRawBody(true);

        $params = $this->validate(
            $rawBody,
            [
                'team_user_id' => ['validators' => ['required']],
                'team_member_status_id' => ['validators' => ['required']]
            ]
        );

        $teamUser = KorwilTeamUser::findFirst($params['team_user_id']);

        if (empty($teamUser)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Tim User tidak ditemukan');
        }

        $status = KorwilTeamMemberStatus::findFirst($params['team_member_status_id']);

        if (empty($status)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Tim User tidak ditemukan');
        }

        $teamUser->team_member_status_id = $params['team_member_status_id'];
        $teamUser->save();

        return new SimpleResponse($teamUser->toDetail());
    }

    public function listPeriode()
    {
        $this->checkIsAuthenticated();

        $getParams = $this->request->get();

        $getParams['limit'] = $this->getDefaultLimit($getParams);
        $getParams['offset'] = array_key_exists('offset', $getParams) ? $getParams['offset'] : 0;
        $getParams['keyword'] = array_key_exists('keyword', $getParams) ? $getParams['keyword'] : '';

        $params =  $this->validate(
            $getParams,
            [
                'limit' => ['validators' => ['digit']],
                'offset' => ['validators' => ['digit']],
                'keyword' => ['validators' => []]
            ]
        );

        $listPeriode = KorsupgahPeriode::find([
            'conditions' => 'lower(nama) like :keyword: AND deleted_at IS NULL',
            'bind' => [
                'keyword' => '%' . $params['keyword'] . '%'
            ],
            'limit' => $params['limit'],
            'offset' => $params['offset']
        ]);

        $result = [];

        foreach ($listPeriode as $periode) {
            $item['id_periode'] = $periode->id;
            $item['nama_periode'] = $periode->nama;

            $result[] = $item;
        }

        $total_record = KorsupgahPeriode::count([
            'conditions' => 'lower(nama) like :keyword: AND deleted_at IS NULL',
            'bind' => [
                'keyword' => '%' . $params['keyword'] . '%'
            ]
        ]);

        return new PaginatedResponse($result, $total_record, $params['limit'], $params['offset']);
    }

    public function copy($id_periode_old, $id_periode_new) {
        // copy korwil_teams, korwil_team_user, korwil_team_instansi
        // from a period to another

        // security: WARNING: if teams from $id_periode_new have already been there,
        // terminate this function.
        $newTeamCount = KorwilTeam::count([
            'conditions' => 'id_periode = :id_periode: AND deleted_at IS NULL',
            'bind' => [
                'id_periode' => $id_periode_new
            ]
        ]);

        if ($newTeamCount > 0) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID periode #' . $id_periode_new . ' sudah dibuat');
        }

        // retrieve the teams from id_periode_old
        $oldTeams = KorwilTeam::find([
            'columns' => ['id', 'name', 'description'],
            'conditions' => 'id_periode = :id_periode: AND deleted_at IS NULL',
            'bind' => [
                'id_periode' => $id_periode_old
            ],
            'order' => 'id'
        ]);

        foreach ($oldTeams as $team ) {
            $teamRow = $team->toArray();
            $team_id[] = $teamRow['id'];
        }
        // security: IF Old Team has not been there, pls terminate 
        if (!isset($team_id)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Team dengan ID periode #' . $id_periode_old . ' belum ada');
        }

        // KorwilTeamUser
        $oldTeamUsers = KorwilTeamUser::find([
            'columns' => ['team_id', 'user_id', 'team_member_status_id'],
            'conditions' => 'team_id IN ({team_id:array}) AND deleted_at IS NULL',
            'bind' => [
                'team_id' => $team_id
            ],
            'order' => 'id'
        ]);

        // populate them and classify them based on team_id
        $oldTeamUsersArray = [];
        foreach($oldTeamUsers as $user) {
            $row = $user->toArray();
            $oldTeamId = strval($row['team_id']); // gunakan strval sbg index array, jangan integer
            if (!isset($oldTeamUsersArray[$oldTeamId])) {
                $oldTeamUsersArray[$oldTeamId] = [$row];
            } else {
                $oldTeamUsersArray[$oldTeamId][] = $row;
            }
        }

        // KorwilTeamInstansi
        $teamInstansis = KorwilTeamInstansi::find([
            'columns' => ['team_id', 'instansi_id'],
            'conditions' => 'team_id IN ({team_id:array}) AND deleted_at IS NULL',
            'bind' => [
                'team_id' => $team_id
            ],
            'order' => 'id'
        ]);

        // populate them and classify them based on team_id
        $oldTeamInstansisArray = [];
        foreach($teamInstansis as $instansi) {
            $row = $instansi->toArray();
            $oldTeamId = strval($row['team_id']);  // gunakan strval sbg index array, jangan integer
            if (!isset($oldTeamInstansisArray[$oldTeamId])) {
                $oldTeamInstansisArray[$oldTeamId] = [$row];
            } else {
                $oldTeamInstansisArray[$oldTeamId][] = $row;
            }
        }

        // Now we have three arrays, let's begin copying the old teams into new ones
        foreach ($oldTeams as $team) {
            $newTeam = new KorwilTeam();
            $newTeam->name = $team->name;
            $newTeam->description = $team->description;
            $newTeam->id_periode = $id_periode_new;
            $newTeam->save(); // simpan team baru

            $newTeamId = $newTeam->id; // penting, the new id of the team
            
            // copy instansi and user
            $oldTeamId = strval($team->id);  // gunakan strval sbg index array, jangan integer
            // iterate $oldTeamUsersArray by the old team_id
            foreach ($oldTeamUsersArray[$oldTeamId] as $teamUser ) {
                $newTeamUser = new KorwilTeamUser();
                $newTeamUser->team_id = $newTeamId; // new team id
                $newTeamUser->user_id = $teamUser['user_id'];
                $newTeamUser->team_member_status_id = $teamUser['team_member_status_id'];
                $newTeamUser->save();
            }

            // iterate $oldTeamInstansisArray by the old team_id
            foreach ($oldTeamInstansisArray[$oldTeamId] as $teamInstansi ) {
                $newTeamInstansi = new KorwilTeamInstansi();
                $newTeamInstansi->team_id = $newTeamId; // new team id
                $newTeamInstansi->instansi_id = $teamInstansi['instansi_id'];
                $newTeamInstansi->save();
            }
        }

        return new ObjectResponse(
            [
                "success" => true,
                "message" => "Pembuatan team periode #".$id_periode_new." berhasil"
            ]
        );
    }
}
