<?php

use idoit\Module\SyneticsJdisc\Graphql\Connector;
use idoit\Module\SyneticsJdisc\Graphql\Mutation\DeleteDevices;
use idoit\Module\SyneticsJdisc\Graphql\Query\IdentifyDevice;
use idoit\Module\SyneticsJdisc\Graphql\Type\DeviceInputType;

/**
 * I-doit -> JDisc Delete Devices View
 *
 * @package     i-doit
 * @subpackage  Reports
 * @author      Paul Kolbovich <pkolbovich@i-doit.org>
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 */
class isys_report_view_jdisc_delete_devices extends isys_report_view_jdisc_availability
{
    /**
     * @param int $type
     *
     * @return int
     */
    protected function getDevicesSize(int $type = 0): int
    {
        $status = implode(',', [C__RECORD_STATUS__ARCHIVED, C__RECORD_STATUS__DELETED]);
        $typeSelector = '';
        if ($type) {
            $typeSelector = "AND isys_obj__isys_obj_type__id = {$type}";
        }

        return (int)$this->database->fetch_row_assoc($this->database->query(
            <<<SQL
                SELECT
                    COUNT(DISTINCT isys_obj__id) AS cnt
                    FROM isys_obj
                    JOIN isys_catg_jdisc_device_information_list
                        ON isys_catg_jdisc_device_information_list__isys_obj__id = isys_obj__id
                    WHERE
                        isys_obj__status IN ({$status})
                        {$typeSelector}
                SQL
        ))['cnt'];
    }

    /**
     * @return void
     */
    public function ajax_request(): void
    {
        header('Content-Type: application/json');

        $serverId = (int) $_POST['server'];
        $callback = $_POST['callback'] ?? '';

        $this->initJDiscMatching($serverId);
        $connector = $this->getConnector($serverId);

        if (!$connector) {
            echo json_encode(['success' => false]);
            exit;
        }

        if ($callback == 'deleteDevices') {
            $this->deleteDevices($connector, $_POST['devices'] ?? []);
        } else {
            $type = (int) $_POST['type'];
            $devicesProcessed = (int) $_POST['devicesProcessed'];
            $devicesSize = $this->getDevicesSize($type);

            $this->listDevices($connector, $type, $devicesProcessed, $devicesSize);
        }
    }

    /**
     * @param Connector $connector
     * @param array     $device
     *
     * @return array
     */
    private function getJDiscData(Connector $connector, array $device): array
    {
        if ($device['serialnumber'] || $device['mac']) {
            $networkInterfaces = [];
            if ($device['mac']) {
                $macs = explode(',', $device['mac']);
                foreach ($macs as $mac) {
                    $networkInterfaces[] = ['physicalAddress' => $mac];
                }
            }

            $query = new IdentifyDevice();

            $query->setSelections([
                'id',
            ]);
            $query->setParameters([
                new DeviceInputType('device', [
                    'serialNumber'      => $device['serialnumber'],
                    'networkInterfaces' => $networkInterfaces,
                ]),
            ]);

            $data = $connector->query($query);

            return $data['device'];
        }

        if ($device['jdiscId']) {
            $objectId = isys_jdisc_dao_matching::instance()
                ->get_object_id_by_device_id($device['jdiscId']);

            return $objectId ? ['id' => $objectId] : [];
        }

        return [];
    }

    /**
     * @return string
     */
    public static function name(): string
    {
        return 'LC__REPORT__VIEW__JDISC_DELETE_DEVICES__TITLE';
    }

    /**
     * @return string
     */
    public static function description(): string
    {
        return 'LC__REPORT__VIEW__JDISC_DELETE_DEVICES__DESCRIPTION';
    }

    /**
     * @return string
     */
    public function template(): string
    {
        return __DIR__ . '/view_jdisc_delete_device.tpl';
    }

    /**
     * @return string
     */
    public static function viewtype(): string
    {
        return 'LC__CMDB__OBJTYPE__CATG';
    }

    /**
     * @param Connector $connector
     * @param array     $devices
     *
     * @return void
     */
    private function deleteDevices(Connector $connector, array $devices): void
    {
        $query = new DeleteDevices();
        $query->setDevices($devices);

        $remainingDevices = $connector->query($query) ?? [];

        echo json_encode([
            'success'          => true,
            'remainingDevices' => $remainingDevices,
        ]);
        exit;
    }

    /**
     * @param Connector $connector
     * @param int       $type
     * @param int       $devicesProcessed
     * @param int       $devicesSize
     *
     * @return void
     */
    private function listDevices(Connector $connector, int $type, int $devicesProcessed, int $devicesSize): void
    {
        $devicesPerRequest = $this->devicesPerRequest;
        $status = implode(',', [C__RECORD_STATUS__ARCHIVED, C__RECORD_STATUS__DELETED]);
        $jdiscTypeId = (int) C__CATG__IDENTIFIER_TYPE__JDISC;

        // get devices
        $devices = [];

        $typeSelector = '';
        if ($type) {
            $typeSelector = "AND isys_obj__isys_obj_type__id = {$type}";
        }

        do {
            $res = $this->database->query(
                <<<SQL
                SELECT
                    isys_obj__id AS id,
                    isys_obj__title AS title,
                    isys_jdisc_mapping__jdisc_serial_number AS mapping_serial_number,
                    isys_jdisc_mapping__jdisc_mac AS mapping_mac,
                    isys_catg_model_list__serial AS model_serial_number,
                    GROUP_CONCAT(DISTINCT isys_catg_log_port_list__mac) AS port_list_mac
                FROM isys_obj
                JOIN isys_catg_jdisc_device_information_list
                    ON isys_catg_jdisc_device_information_list__isys_obj__id = isys_obj__id
                LEFT JOIN isys_jdisc_mapping
                    ON isys_jdisc_mapping__reference_id = isys_obj__id
                LEFT JOIN isys_catg_model_list
                    ON isys_catg_model_list__isys_obj__id = isys_obj__id
                LEFT JOIN isys_catg_log_port_list
                    ON isys_catg_log_port_list__isys_obj__id = isys_obj__id
                LEFT JOIN isys_catg_identifier_list
                    ON
                        isys_catg_identifier_list__isys_obj__id = isys_obj__id
                        AND isys_catg_identifier_list__isys_catg_identifier_type__id = {$jdiscTypeId}
                WHERE
                    isys_obj__status IN ({$status})
                    {$typeSelector}
                GROUP BY isys_obj__id
                ORDER BY id
                LIMIT {$devicesProcessed}, {$devicesPerRequest}
                SQL
            );
            while ($row = $this->database->fetch_row_assoc($res)) {
                $devicesProcessed++;
                $device = [
                    'id'           => $row['id'],
                    'title'        => $row['title'],
                    'mac'          => $row['mapping_mac'] ?? $row['port_list_mac'],
                    'serialnumber' => $row['mapping_serial_number'] ?? $row['model_serial_number'],
                    'jdisc'        => [],
                ];
                $device['jdisc'] = $this->getJDiscData($connector, $device);

                // skip devices that cannot be found in the selected JDisc server
                if (!$device['jdisc']) {
                    continue;
                }

                $devices[] = [
                    'id'    => $device['id'],
                    'title' => $device['title'],
                    'jdisc' => $device['jdisc'],
                ];

                if (count($devices) == $devicesPerRequest) {
                    break;
                }
            }
        } while (count($devices) < $devicesPerRequest && $devicesProcessed < $devicesSize);

        echo json_encode([
            'success'          => true,
            'devices'          => $devices,
            'caller'           => (string) $_POST['caller'],
            'devicesProcessed' => $devicesProcessed,
            'devicesSize'      => $devicesSize,
        ]);
        exit;
    }
}
