<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\Utility\Inflector;
use Cake\Utility\Hash;
use Cake\Utility\Text;
use \Cake\Database\Expression\QueryExpression;
use Cake\Error\Debugger;
use Cake\Http\Exception\NotFoundException;
use Cake\ORM\TableRegistry;

class SharingGroupsController extends AppController
{
    public $filterFields = ['SharingGroups.uuid', 'SharingGroups.name', 'description', 'releasability', 'Organisations.name', 'Organisations.uuid'];
    public $quickFilterFields = ['SharingGroups.uuid', ['SharingGroups.name' => true], ['description' => true], ['releasability' => true]];
    public $containFields = ['SharingGroupOrgs', 'Organisations', 'Users' => ['fields' => ['id', 'username']]];

    public function index()
    {
        $currentUser = $this->ACL->getUser();
        $conditions = [];
        $this->CRUD->index([
            'contain' => $this->containFields,
            'filters' => $this->filterFields,
            'quickFilters' => $this->quickFilterFields,
            'conditions' => $conditions,
            'afterFind' => function ($row) use ($currentUser) {
                if (empty($currentUser['role']['perm_community_admin'])) {
                    $orgFound = false;
                    if (!empty($row['sharing_group_orgs'])) {
                        foreach ($row['sharing_group_orgs'] as $org) {
                            if ($org['id'] === $currentUser['organisation_id']) {
                                $orgFound = true;
                            }
                        }
                    }
                    if ($row['organisation_id'] !== $currentUser['organisation_id'] && !$orgFound) {
                        return false;
                    }
                }
                return $row;
            }
        ]);
        $responsePayload = $this->CRUD->getResponsePayload();
        if (!empty($responsePayload)) {
            return $responsePayload;
        }
    }

    public function add()
    {
        $currentUser = $this->ACL->getUser();
        $this->CRUD->add([
            'override' => [
                'user_id' => $this->ACL->getUser()['id']
            ],
            'beforeSave' => function($data) use ($currentUser) {
                if (!$currentUser['role']['perm_community_admin']) {
                    $data['organisation_id'] = $currentUser['organisation_id'];
                }
                return $data;
            }
        ]);
        $dropdownData = [
            'organisation' => $this->getAvailableOrgForSg($this->ACL->getUser())
        ];
        $responsePayload = $this->CRUD->getResponsePayload();
        if (!empty($responsePayload)) {
            return $responsePayload;
        }
        $this->set(compact('dropdownData'));
    }

    public function view($id)
    {
        $currentUser = $this->ACL->getUser();
        $this->CRUD->view($id, [
            'contain' => ['SharingGroupOrgs', 'Organisations', 'Users' => ['fields' => ['id', 'username']]],
            'afterFind' => function($data) use ($currentUser) {
                if (empty($currentUser['role']['perm_community_admin'])) {
                    $orgFound = false;
                    if (!empty($data['sharing_group_orgs'])) {
                        foreach ($data['sharing_group_orgs'] as $org) {
                            if ($org['id'] === $currentUser['organisation_id']) {
                                $orgFound = true;
                            }
                        }
                    }
                    if ($data['organisation_id'] !== $currentUser['organisation_id'] && !$orgFound) {
                        return null;
                    }
                }
                return $data;
            }
        ]);
        $responsePayload = $this->CRUD->getResponsePayload();
        if (!empty($responsePayload)) {
            return $responsePayload;
        }
    }

    public function edit($id = false)
    {
        $params = [];
        $currentUser = $this->ACL->getUser();
        if (empty($currentUser['role']['perm_community_admin'])) {
            $params['conditions'] = ['organisation_id' => $currentUser['organisation_id']];
        }
        $params['fields'] = ['name', 'releasability', 'description', 'active'];
        $this->CRUD->edit($id, $params);
        $responsePayload = $this->CRUD->getResponsePayload();
        if (!empty($responsePayload)) {
            return $responsePayload;
        }
        $dropdownData = [
            'organisation' => $this->getAvailableOrgForSg($this->ACL->getUser())
        ];
        $this->set(compact('dropdownData'));
        $this->render('add');
    }

    public function delete($id)
    {
        $currentUser = $this->ACL->getUser();
        $params = [];
        if (empty($currentUser['role']['perm_community_admin'])) {
            $params['conditions'] = ['organisation_id' => $currentUser['organisation_id']];
        }
        $this->CRUD->delete($id, $params);
        $responsePayload = $this->CRUD->getResponsePayload();
        if (!empty($responsePayload)) {
            return $responsePayload;
        }
    }

    public function addOrg($id)
    {
        $currentUser = $this->ACL->getUser();
        $sharingGroup = $this->SharingGroups->get($id, [
            'contain' => 'SharingGroupOrgs'
        ]);
        if (empty($currentUser['role']['perm_community_admin'])) {
            if ($sharingGroup['organisation_id'] !== $currentUser['organisation_id']) {
                $sharingGroup = null;
            }
        }
        if (empty($sharingGroup)) {
            throw new NotFoundException(__('Invalid SharingGroup.'));
        }
        $conditions = [];
        $containedOrgIds = array_values(\Cake\Utility\Hash::extract($sharingGroup, 'sharing_group_orgs.{n}.id'));
        if (!empty($containedOrgIds)) {
            $conditions = [
                'NOT' => [
                    'id IN' => $containedOrgIds
                ]
            ];
        }
        $dropdownData = [
            'organisation' => $this->SharingGroups->Organisations->find('list', [
                'sort' => ['name' => 'asc'],
                'conditions' => $conditions
            ])->toArray()
        ];
        if ($this->request->is('post')) {
            $input = $this->request->getData();
            if (empty($input['organisation_id'])) {
                throw new InvalidArgumentException(__('No organisation IDs passed.'));
            }
            if (!is_array($input['organisation_id'])) {
                $input['organisation_id'] = [$input['organisation_id']];
            }
            $result = true;
            $this->SGO = TableRegistry::getTableLocator()->get('SGOs');
            foreach ($input['organisation_id'] as $org_id) {
                $additional_data = [];
                if (!empty($input['extend'])) {
                    $additional_data['extend'] = $input['extend'];
                }
                $result &= $this->SGO->attach($sharingGroup['id'], $org_id, $additional_data);
            }
            if ($result) {
                $message = __('Organisation(s) added to the sharing group.');
            } else {
                $message = __('Organisation(s) could not be added to the sharing group.');
            }
            if ($this->ParamHandler->isRest() || $this->ParamHandler->isAjax()) {
                if ($result) {
                    $savedData = $this->SharingGroups->get($id, [
                        'contain' => 'SharingGroupOrgs'
                    ]);
                    return $this->RestResponse->ajaxSuccessResponse(Inflector::singularize($this->SharingGroups->getAlias()), 'addOrg', $savedData, $message);
                } else {
                    return $this->RestResponse->ajaxFailResponse(Inflector::singularize($this->SharingGroups->getAlias()), 'addOrg', $sharingGroup, $message);;
                }
            } else {
                if ($result) {
                    $this->Flash->success($message);
                } else {
                    $this->Flash->error($message);
                }
                $this->redirect(['action' => 'view', $id]);
            }
        }
        $this->set(compact('dropdownData'));
    }

    public function removeOrg($id, $org_id)
    {
        $currentUser = $this->ACL->getUser();
        $sharingGroup = $this->SharingGroups->get($id, [
            'contain' => 'SharingGroupOrgs'
        ]);
        if (empty($currentUser['role']['perm_community_admin'])) {
            if ($sharingGroup['organisation_id'] !== $currentUser['organisation_id']) {
                $sharingGroup = null;
            }
        }
        if (empty($sharingGroup)) {
            throw new NotFoundException(__('Invalid SharingGroup.'));
        }
        if ($this->request->is('post')) {
            $this->SGO = TableRegistry::getTableLocator()->get('SGOs');
            $result = (bool)$this->SharingGroups->SharingGroupOrgs->unlink($sharingGroup['id'], $org_id);
            if ($result) {
                $message = __('Organisation(s) removed from the sharing group.');
            } else {
                $message = __('Organisation(s) could not be removed to the sharing group.');
            }
            if ($this->ParamHandler->isRest() || $this->ParamHandler->isAjax()) {
                if ($result) {
                    $savedData = $this->SharingGroups->get($id, [
                        'contain' => 'SharingGroupOrgs'
                    ]);
                    return $this->RestResponse->ajaxSuccessResponse(Inflector::singularize($this->SharingGroups->getAlias()), 'removeOrg', $savedData, $message);
                } else {
                    return $this->RestResponse->ajaxFailResponse(Inflector::singularize($this->SharingGroups->getAlias()), 'removeOrg', $sharingGroup, $message);
                    ;
                }
            } else {
                if ($result) {
                    $this->Flash->success($message);
                } else {
                    $this->Flash->error($message);
                }
                $this->redirect(['action' => 'view', $id]);
            }
        }
        $this->set('scope', 'sharing_groups');
        $this->set('id', $org_id);
        $this->set('sharingGroup', $sharingGroup);
        $this->set('deletionText', __('Are you sure you want to remove Organisation #{0} from Sharing group #{1}?', $org_id, $sharingGroup['id']));
        $this->set('postLinkParameters', ['action' => 'removeOrg', $id, $org_id]);
        $this->viewBuilder()->setLayout('ajax');
        $this->render('/genericTemplates/delete');
    }

    public function listOrgs($id)
    {
        $sharingGroup = $this->SharingGroups->find()->where(['id' => $id])->contain(['SharingGroupOrgs'])->first();
        foreach ($sharingGroup['sharing_group_orgs'] as $k => $org) {
            $sharingGroup['sharing_group_orgs'][$k]['extend'] = $org['_joinData']['extend'];
        }
        $params = $this->ParamHandler->harvestParams(['quickFilter']);
        if (!empty($params['quickFilter'])) {
            foreach ($sharingGroup['sharing_group_orgs'] as $k => $org) {
                if (strpos($org['name'], $params['quickFilter']) === false) {
                    unset($sharingGroup['sharing_group_orgs'][$k]);
                }
            }
            $sharingGroup['sharing_group_orgs'] = array_values($sharingGroup['sharing_group_orgs']);
        }
        $this->set('sharing_group_id', $id);
        $this->set('sharing_group_orgs', $sharingGroup['sharing_group_orgs']);
    }

    private function getAvailableOrgForSg($user)
    {
        $organisations = [];
        if (!empty($user['role']['perm_community_admin'])) {
            $organisations = $this->SharingGroups->Organisations->find('list')->order(['name' => 'ASC'])->toArray();
        } else {
            $organisations = $this->SharingGroups->Organisations->find('list', [
                'sort' => ['name' => 'asc'],
                'conditions' => [
                    'id' => $user['organisation_id']
                ]
            ])->toArray();
        }
        return $organisations;
    }
}
