<?php declare(strict_types = 1);

namespace idoit\Module\SyneticsJdisc\Controller;

use idoit\Module\SyneticsJdisc\Controller\Response\ArrayResponse;
use idoit\Module\SyneticsJdisc\Controller\Response\NotFoundResponse;
use idoit\Module\SyneticsJdisc\Controller\Table\SearchParams;
use idoit\Module\SyneticsJdisc\Model\JDiscProfileDao;
use idoit\Module\SyneticsJdisc\View\SyncProfile;
use idoit\Module\SyneticsJdisc\View\SyncProfileList;
use isys_application;
use isys_component_filemanager;
use isys_format_json as JSON;
use isys_module_synetics_jdisc;
use isys_notify;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

class SyncProfileController extends AbstractController
{
    private ?JDiscProfileDao $dao = null;

    /**
     * @return JDiscProfileDao
     * @throws \Exception
     */
    private function getDao(): JDiscProfileDao
    {
        if (null === $this->dao) {
            $this->dao = isys_application::instance()->container->get('idoit.jdisc.sync-profile.dao');
        }
        return $this->dao;
    }

    /**
     * @return Response
     * @throws \Exception
     */
    public function page(): Response
    {
        $navMode = (int)$_POST[C__GET__NAVMODE];
        if ($navMode === C__NAVMODE__NEW) {
            return SyncProfile::factory()->setMode($navMode)->render();
        }

        $id = null;

        if (!empty($_POST[C__GET__ID])) {
            $id = (int)((is_array($_POST[C__GET__ID]) && count($_POST[C__GET__ID]) === 1) ? current($_POST[C__GET__ID]) : $_POST[C__GET__ID]);
        }
        $syncProfile = SyncProfile::factory()->setMode($navMode)->setId($id);

        if ($navMode === C__NAVMODE__EDIT && $id > 0) {
            return $syncProfile->render();
        }

        if ($navMode === C__NAVMODE__SAVE) {
            $dao = $syncProfile->getDao();
            $data = $dao->prepareData();
            $syncProfile->setValidationErrors($dao->validateData($data));

            if (null === $id) {
                $syncProfile->unsetValidationError('id');
            }

            if ($navMode === C__NAVMODE__SAVE && !$syncProfile->hasValidationErrors() && $dao->save($id, $data)) {
                isys_notify::success($syncProfile->language->get('LC__JDISC__SYNC_PROFILES__SAVED'));
            }

            return $syncProfile->render();
        }

        if ($navMode === C__NAVMODE__EXPORT && !empty($_POST[C__GET__ID])) {
            $this->exportProfiles();
        }

        return SyncProfileList::factory()->setMode($navMode)->render();
    }

    /**
     * @return void
     */
    private function exportProfiles(): void
    {
        $ids = $_POST[C__GET__ID];
        $result_set = [];
        $jdiscModule = isys_module_synetics_jdisc::factory();
        $profileName = '';

        foreach ($ids as $id) {
            $profile = $jdiscModule->load_profile((int)$id);
            $profileName = $profile['profiles']['title'] ?? '';

            $result_set[] = $profile;
        }

        // @see ID-9572 Use proper names for JDisc profile exports.
        $filename = count($ids) > 1
            ? 'jdisc-profiles'
            : "jdisc-profile_{$profileName}";

        $filename = \idoit\Component\Helper\Purify::formatFilename("{$filename}.json");

        isys_component_filemanager::sendInline(
            JSON::encode($result_set),
            $filename,
            'application/json'
        );
    }

    /**
     * @return Response
     */
    public function handleEntry(string $id): Response
    {
        $navMode = (int)$_POST[C__GET__NAVMODE];
        if ((!$id && !in_array($navMode, [C__NAVMODE__EDIT, C__NAVMODE__SAVE])) || $navMode === C__NAVMODE__CANCEL) {
            return SyncProfileList::factory()->setMode($navMode)->render();
        }

        $syncProfile = SyncProfile::factory()->setMode($navMode)->setId((int)$id);
        if ($navMode === C__NAVMODE__SAVE) {
            $dao = $syncProfile->getDao();
            $data = $dao->prepareData();
            $syncProfile->setValidationErrors($dao->validateData($data));

            if ($navMode === C__NAVMODE__SAVE && !$syncProfile->hasValidationErrors() && $dao->save((int)$id, $data)) {
                isys_notify::success($syncProfile->language->get('LC__JDISC__SYNC_PROFILES__SAVED'));
            }
        }

        return $syncProfile->render();
    }

    /**
     * @param Request $request
     * @return Response
     */
    public function find(Request $request): Response
    {
        $search = SearchParams::fromParams($request->get('params'));

        return new ArrayResponse(
            $this->getDao()->getData(null, $search),
            $this->getDao()->getCount(),
        );
    }

    /**
     * @param string $id
     * @return Response
     */
    public function get(string $id): Response
    {
        $result = $this->getDao()->get((int) $id);
        if ($result === null) {
            return new NotFoundResponse('SyncProfile');
        }
        return new JsonResponse($result);
    }

    /**
     * @param Request $request
     * @param int|null $id
     * @return Response
     */
    public function save(Request $request, ?int $id = null): Response
    {
        $data = json_decode($request->getContent(), true);
        if (empty($data)) {
            return new JsonResponse(['error' => 'No data provided'], Response::HTTP_BAD_REQUEST);
        }

        if (!empty($id)) {
            $data['id'] = $id;
        } else {
            unset($data['id']);
        }

        try {
            $profileId = $this->getDao()->saveProfile($data);
        } catch (Throwable $e) {
            return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
        if (empty($profileId)) {
            return new JsonResponse(['error' => 'Profile save error'], Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        return new JsonResponse(['id' => $profileId]);
    }

    /**
     * @param string $id
     * @return Response
     */
    public function delete(string $id): Response
    {
        $result = $this->getDao()->delete([$id]);
        if (!$result) {
            return new JsonResponse(['error' => 'Pofile deletion error'], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
        return new JsonResponse(['success' => true]);
    }

    /**
     * @param int $id
     * @return Response
     * @todo getProfile is deprecated, use get when its ready
     */
    public function getAssignments(int $id): Response
    {
        $profile = $this->getDao()->getProfile($id);
        if ($profile === null) {
            return new NotFoundResponse('SyncProfile');
        }
        $assignments = [];
        foreach ($profile['object_type_assignments'] as $assignment) {
            $assignments[$assignment['jdisc_type']] = $assignment['object_type'];
        }
        return new JsonResponse($assignments);
    }

    /**
     * @param Request $request
     * @return Response
     */
    public function export(Request $request): ?Response
    {
        $ids = explode(',', $request->get('ids'));
        if (empty($ids) || !is_array($ids)) {
            return new JsonResponse(['error' => 'No data provided'], Response::HTTP_BAD_REQUEST);
        }

        return $this->getDao()->exportProfiles($ids);
    }

    /**
     * @param Request $request
     * @return Response
     */
    public function getFormOptions(Request $request): Response
    {
        $serverId = (int) $request->get('serverId');
        $serverDao = isys_application::instance()->container->get('idoit.jdisc.server.dao');
        $server = $serverDao->getConfiguration($serverId);
        if ($server === null) {
            return new NotFoundResponse('DiscoveryServer');
        }

        try {
            $result = $this->getDao()->getFormOptions($serverId);
            return new JsonResponse($result);
        } catch (Throwable $e) {
            return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }
}
